Compare commits

..

365 Commits
1.4.7 ... 1.6.1

Author SHA1 Message Date
Davidson Gomes
45e03d87c7 Merge branch 'release/1.6.1' 2023-12-22 11:44:12 -03:00
Davidson Gomes
3e358e5d26 version: 1.6.1 2023-12-22 11:43:58 -03:00
Davidson Gomes
dc5dae04eb fix: when deleting a message in whatsapp, delete the message in chatwoot too 2023-12-22 11:43:10 -03:00
Davidson Gomes
9128b1f47d fix: when deleting a message in whatsapp, delete the message in chatwoot too 2023-12-22 11:43:03 -03:00
Davidson Gomes
16a8226ba7 Merge pull request #317 from jaison-x/pr
fix: when deleting a message in whatsapp, delete the message in chatwoot too
2023-12-21 16:37:01 -03:00
jaison-x
9ecaf3199d Merge branch 'pr' of https://github.com/jaison-x/evolution-api into pr 2023-12-21 07:42:37 -03:00
jaison-x
a44cd0373e fix: simple adjust in key object 2023-12-21 07:42:33 -03:00
jaison-x
2c0b629302 Update whatsapp.service.ts 2023-12-21 00:23:33 -03:00
jaison-x
89a37a1771 fix: show message Connection successfully established after a sucessfull connection on chatwoot 2023-12-20 18:11:41 -03:00
jaison-x
cadc038966 Merge remote-tracking branch 'upstream/develop' into pr 2023-12-20 17:54:52 -03:00
jaison-x
07e8449379 fix: when deleting a message in whatsapp, delete the message in chatwoot too
The message model schema was changed. Old format in message model was field chatwootMessageId. Now we have a document chatwoot with new properties.

I cant find a simple way to create a migration function up then the old field was no migrate to new format.
2023-12-20 17:53:37 -03:00
Davidson Gomes
71e908ad1a Merge pull request #312 from stgcompany/develop
Exclude all .env files on .gitignore and renamed one to .env.example
2023-12-20 12:22:03 -03:00
Davidson Gomes
035c85b775 Merge pull request #313 from gabrielpastori1/issue-template
Add issue templates
2023-12-20 12:21:06 -03:00
Gabriel Pastori
a87b753151 Update issue templates 2023-12-20 12:13:24 -03:00
Eduardo Chaves
edaa4aff7e Add any .env file to .gitignore 2023-12-20 10:31:14 -03:00
Eduardo Chaves
be02610349 Renamed .env to .env.example 2023-12-20 10:29:32 -03:00
Davidson Gomes
1f65731165 fix: Add options to disable docs and manager 2023-12-20 10:03:44 -03:00
Davidson Gomes
fb61fb7849 Merge pull request #310 from gabrielpastori1/disable-docs-manager
Add options to disable docs and manager
2023-12-20 10:02:46 -03:00
Davidson Gomes
060a945aea fix: Fix the problem when disconnecting the instance and connecting again using mongodb 2023-12-20 09:56:53 -03:00
Davidson Gomes
2797250f34 Merge branch 'develop' of github.com:EvolutionAPI/evolution-api into develop 2023-12-20 09:56:32 -03:00
Davidson Gomes
97b3f9b3c7 fix: Fix the problem when disconnecting the instance and connecting again using mongodb 2023-12-20 09:55:51 -03:00
Gabriel Pastori
9363301d2a Add DISABLE_DOCS and DISABLE_MANAGER 2023-12-19 21:18:40 -03:00
Davidson Gomes
d93a826e28 Merge pull request #309 from jaison-x/pr
fix: message can be undefined
2023-12-19 18:59:59 -03:00
jaison-x
244fe0835e Update chatwoot.service.ts
fix: message can be undefined
2023-12-19 18:49:31 -03:00
Davidson Gomes
5f1a5d6589 Merge pull request #308 from PurpShell/fix/message-retry
Fix: message retry mechanism
2023-12-19 17:34:39 -03:00
Rajeh Taher
4e27c22292 fix: message retry 2023-12-19 22:28:50 +02:00
Davidson Gomes
53ee270096 Merge pull request #307 from gabrielpastori1/chatwoot-format
Chatwoot Agent Name
2023-12-19 17:15:32 -03:00
Gabriel Pastori
a00ad20c08 chatwoot agent available_name 2023-12-19 16:41:52 -03:00
Davidson Gomes
e8764dd1c6 fix: Fix the problem when disconnecting the instance and connecting again using mongodb 2023-12-19 14:55:16 -03:00
Davidson Gomes
a869d38499 Merge branch 'develop' of github.com:EvolutionAPI/evolution-api into develop 2023-12-19 14:27:47 -03:00
Davidson Gomes
7bf7c96587 Merge pull request #301 from drauber/addLogInfo
Add connected number and instance name to connected log
2023-12-19 14:27:41 -03:00
Davidson Gomes
72b857a92f Merge pull request #299 from gabrielpastori1/chatwoot-format
Chatwoot format
2023-12-19 14:27:05 -03:00
Douglas Rauber at Nitro
380d6a43a5 Add connected number and instance name to connected log 2023-12-19 08:02:29 -03:00
Gabriel Pastori
076f2b492e fix: chatwoot media process 2023-12-18 21:23:56 -03:00
Davidson Gomes
547f981c47 fix: adjusts in typebot 2023-12-18 16:46:04 -03:00
Davidson Gomes
8bfc62a3b2 fix: adjusts in typebot 2023-12-18 16:27:37 -03:00
Davidson Gomes
d39776a314 fix: fixed the pairing code 2023-12-18 15:27:22 -03:00
Davidson Gomes
35641d0543 fix: fixed the pairing code 2023-12-18 15:24:19 -03:00
Davidson Gomes
038cd6f149 Merge pull request #293 from gabrielpastori1/chatwoot-format
Chatwoot format
2023-12-18 12:15:00 -03:00
Davidson Gomes
38978dd447 test: adjusts baileys lids 2023-12-18 12:07:02 -03:00
Gabriel Pastori
fb24b7eaa7 Merge branch 'develop' into chatwoot-format 2023-12-17 13:30:54 -03:00
Gabriel Pastori
b4ce45bc4b Add new env and fix message formatting in Chatwoot to changelog 2023-12-17 13:25:03 -03:00
Gabriel Pastori
8d04198309 fix: monospace and bold 2023-12-17 13:24:43 -03:00
Davidson Gomes
da796347c4 fix: include instance Id field in the instance configuration 2023-12-17 09:37:18 -03:00
Davidson Gomes
2d6a29664a fix: include instance Id field in the instance configuration 2023-12-17 07:59:24 -03:00
Davidson Gomes
4ba5cfceaf fix: include instance Id field in the instance configuration 2023-12-17 07:50:17 -03:00
Davidson Gomes
7cc324e1c0 fix: include instance Id field in the instance configuration 2023-12-17 07:04:33 -03:00
Davidson Gomes
cf89601269 fix: include instance Id field in the instance configuration 2023-12-17 06:59:05 -03:00
Davidson Gomes
c07e23bf8d Merge pull request #290 from gabrielpastori1/chatwoot-format
Chatwoot format
2023-12-17 06:32:37 -03:00
Gabriel Pastori
5aa89d85f3 fix: remove comments 2023-12-16 18:39:46 -03:00
Gabriel Pastori
4ed1edf53d chatwoot_sign_delimiter 2023-12-16 17:23:39 -03:00
Gabriel Pastori
1be1326b52 Refactor message formatting in ChatwootService (Bold, italic, etc) 2023-12-16 15:58:01 -03:00
Davidson Gomes
42ae7d1568 Merge pull request #286 from gomessguii/feature/dockerfile-optimization
Dockerfile modified to use multi-stage build
2023-12-15 14:51:49 -03:00
Guilherme Oliveira
b781c83545 Dockerfile modified to use multi-stage build 2023-12-15 14:46:31 -03:00
Davidson Gomes
e48cea18e7 Merge pull request #283 from gabrielpastori1/typeboot-keep-open
simple add keep open
2023-12-15 13:53:06 -03:00
Gabriel Pastori
ff82987144 simple add keep open 2023-12-15 12:39:07 -03:00
Davidson Gomes
f612a45550 fix: correction sending s3/minio media to chatwoot and typebot 2023-12-14 17:20:37 -03:00
Davidson Gomes
182dce4840 fix: correction sending s3/minio media to chatwoot and typebot 2023-12-14 16:42:03 -03:00
Davidson Gomes
4e41e072d6 fix: correction sending s3/minio media to chatwoot and typebot 2023-12-14 16:13:15 -03:00
Davidson Gomes
a369c16db8 fix: correction sending s3/minio media to chatwoot and typebot 2023-12-14 15:59:06 -03:00
Davidson Gomes
1fc820787a fix: correction sending s3/minio media to chatwoot and typebot 2023-12-14 15:57:34 -03:00
Davidson Gomes
d3a83ba89e fix: correction sending s3/minio media to chatwoot and typebot 2023-12-14 15:35:17 -03:00
Davidson Gomes
20fb66e2f7 fix: correction sending s3/minio media to chatwoot and typebot 2023-12-14 11:50:05 -03:00
Davidson Gomes
a44646161b fix: variables in typebot 2023-12-14 08:35:45 -03:00
Davidson Gomes
87027ea2d0 update: manager 2023-12-12 18:16:02 -03:00
Davidson Gomes
c9757cbb4b fix: fixed lids messages 2023-12-12 17:45:12 -03:00
Davidson Gomes
9a8f4aefe0 Merge tag '1.6.0' into develop
* Added AWS SQS Integration
* Added support for new typebot API
* Added endpoint sendPresence
* New Instance Manager
* Added auto_create to the chatwoot set to create the inbox automatically or not
* Added reply, delete and message reaction in chatwoot v3.3.1

* Adjusts in proxy
* Adjusts in start session for Typebot
* Added mimetype field when sending media
* Ajusts in validations to messages.upsert
* Fixed messages not received: error handling when updating contact in chatwoot
* Fix workaround to manage param data as an array in mongodb
* Removed await from webhook when sending a message
* Update typebot.service.ts - element.underline change ~ for *
* Adjusts in proxy
* Removed api restart on receiving an error
* Fixes in mongodb and chatwoot
* Adjusted return from queries in mongodb
* Added restart instance when update profile picture
* Correction of chatwoot functioning with admin flows
* Fixed problem that did not generate qrcode with the chatwoot_conversation_pending option enabled
* Fixed issue where CSAT opened a new ticket when reopen_conversation was disabled
* Fixed issue sending contact to Chatwoot via iOS

- Chatwoot: v3.3.1
- Typebot: v2.20.0
2023-12-12 17:44:42 -03:00
Davidson Gomes
3545b80050 Merge branch 'release/1.6.0' 2023-12-12 17:44:24 -03:00
Davidson Gomes
379855714e version: 1.6.0 2023-12-12 17:44:00 -03:00
Davidson Gomes
ff06cd7643 feat: Added support for new typebot API 2023-12-12 16:55:46 -03:00
Davidson Gomes
ade3952016 fix: Fixed issue sending contact to Chatwoot via iOS 2023-12-12 16:28:01 -03:00
Davidson Gomes
f246516a6e fix: fixed issue where CSAT opened a new ticket when reopen_conversation was disabled 2023-12-12 16:08:09 -03:00
Davidson Gomes
c296bf4178 fix: Fixed problem that did not generate qrcode with the chatwoot_conversation_pending option enabled 2023-12-12 15:46:10 -03:00
Davidson Gomes
1568554a1c feat: added reply, delete and message reaction in chatwoot v3.3.1 2023-12-12 15:24:54 -03:00
Davidson Gomes
ae66be197e feat: added reply, delete and message reaction in chatwoot v3.3.1 2023-12-12 15:16:09 -03:00
Davidson Gomes
3e904aa160 fix: correction of chatwoot functioning with admin flows 2023-12-12 13:56:47 -03:00
Davidson Gomes
64c1440c46 fix: correction of chatwoot functioning with admin flows 2023-12-12 13:56:41 -03:00
Davidson Gomes
f069a41390 fix: added restart instance when update profile pricture 2023-12-11 18:17:18 -03:00
Davidson Gomes
d4a33e2290 fix: added restart instance when update profile pricture 2023-12-11 18:16:11 -03:00
Davidson Gomes
7ee5bcecff fix: added restart instance when update profile pricture 2023-12-11 18:15:24 -03:00
Davidson Gomes
48f6ee8846 feat: added auto_create to the chatwoot set to create the inbox automatically or not 2023-12-11 17:32:19 -03:00
Davidson Gomes
7a24f52782 feat: added auto_create to the chatwoot set to create the inbox automatically or not 2023-12-11 17:32:07 -03:00
Davidson Gomes
324d46120b feat: new manager 2023-12-11 15:31:43 -03:00
Davidson Gomes
87baec5ff8 Merge pull request #250 from gabrielpastori1/manager
Add Manager
2023-12-11 15:27:43 -03:00
Gabriel Pastori
b2e144f35c add manager 2023-12-11 15:06:42 -03:00
Davidson Gomes
87a8e25662 Merge pull request #249 from gabrielpastori1/typebot-auto-create-session
fix: only create if is paused
2023-12-11 12:57:51 -03:00
Gabriel Pastori
8e88f00fb2 fix: only create if is paused 2023-12-11 12:42:09 -03:00
Davidson Gomes
d14505d59a Merge pull request #248 from gabrielpastori1/fix-chatwoot-find
Fix chatwoot find
2023-12-11 12:32:19 -03:00
Davidson Gomes
1e6d4347fa Merge branch 'develop' of github.com:EvolutionAPI/evolution-api into develop 2023-12-11 12:09:08 -03:00
Davidson Gomes
b8d9a8c072 fix: adjusted return from queries in mongodb 2023-12-11 12:08:58 -03:00
Gabriel Pastori
fd15ae5e8c Fix condition to check for empty result object 2023-12-11 12:00:33 -03:00
Davidson Gomes
fb6377414b Merge pull request #237 from gabrielpastori1/add-send-presence
Add sendPresence
2023-12-11 10:47:26 -03:00
Davidson Gomes
9a5dbe055e fix: adjusts in connection 2023-12-08 18:44:52 -03:00
Gabriel Pastori
42dd280aca change sendPresence from sendMessage to chat 2023-12-08 18:40:48 -03:00
Davidson Gomes
41b2946cdc Merge branch 'develop' of github.com:EvolutionAPI/evolution-api into develop 2023-12-06 15:22:08 -03:00
Davidson Gomes
a90f0f2c59 Fixes in mongodb and chatwoot 2023-12-06 15:21:50 -03:00
Gabriel Pastori
4222c0e53b Fix logger message in sendPresence route 2023-12-06 00:32:27 -03:00
Gabriel Pastori
ee0f0f0be0 add send presence router 2023-12-06 00:31:35 -03:00
Davidson Gomes
f8d874453c Merge pull request #233 from gabrielpastori1/typebot-auto-create-session
Add session creation for typebot service
2023-12-05 18:49:31 -03:00
Gabriel Pastori
aa891489f0 Add session creation for typebot service 2023-12-03 21:00:26 -03:00
Davidson Gomes
4c69b059d4 proxy 2023-12-01 21:24:38 -03:00
Davidson Gomes
359bd9f762 fix: adjusts in proxy 2023-12-01 20:09:22 -03:00
Davidson Gomes
2de0b61726 fix: adjusts in proxy 2023-12-01 20:09:19 -03:00
Davidson Gomes
d75163aa57 test: adjusts wasocket 2023-12-01 15:04:57 -03:00
Davidson Gomes
e49f30641e test: adjusts wasocket 2023-12-01 14:30:20 -03:00
Davidson Gomes
1631c2c342 test: adjusts wasocket 2023-12-01 09:42:56 -03:00
Davidson Gomes
cf7de369b2 test: adjusts wasocket 2023-12-01 08:22:40 -03:00
Davidson Gomes
78c03d8f2f test: adjusts wasocket 2023-12-01 08:21:36 -03:00
Davidson Gomes
876320b849 feat: added compatibility with typebot v2 2023-11-30 17:13:05 -03:00
Davidson Gomes
a1d13f8ff3 changelog 2023-11-30 07:12:14 -03:00
Davidson Gomes
3c19bdfaa9 fix: Removed await from webhook when sending a message 2023-11-30 07:09:11 -03:00
Davidson Gomes
4fa895086e fix: adjusts in validation to messages.upsert 2023-11-30 07:02:25 -03:00
Davidson Gomes
9945d8debb Merge branch 'develop' of github.com:EvolutionAPI/evolution-api into develop 2023-11-30 07:01:48 -03:00
Davidson Gomes
4362de2198 fix: adjusts in validation to messages.upsert 2023-11-30 07:01:26 -03:00
Davidson Gomes
a5c5879e4f fix: adjusts in validation to messages.upsert 2023-11-30 07:01:08 -03:00
Davidson Gomes
1a57f4f33d Merge pull request #215 from suissa/patch-3
Update typebot.service.ts - element.underline change ~ for *
2023-11-29 08:47:52 -03:00
Davidson Gomes
a99e173168 Merge pull request #224 from jaison-x/pr
fix: workaround to manage param data as an array in mongodb
2023-11-29 08:46:12 -03:00
Davidson Gomes
e02a28f61e Merge pull request #228 from raimartinsb/develop
fix messages not received: error handling when updating contact
2023-11-29 08:45:24 -03:00
raimartinsb
26d3ff97ce fix messages not received: error handling when updating contact 2023-11-28 11:10:29 -03:00
Davidson Gomes
57fb3c9785 fix: fixed lids messages 2023-11-27 19:58:23 -03:00
Davidson Gomes
edeb970a82 fix: fixed lids messages 2023-11-27 19:57:59 -03:00
jaison-x
e17baddf01 fix: workaround to manage param data as an array in mongodb
When saving data from a group session (sender-key-xxxxx@g.us::xxxxx::xx) we receive the data param as an array.
In mongodb we can't save an array as a root document. Bacause this, in this case we save the array in a property called content_array.
2023-11-24 18:59:19 -03:00
Davidson Gomes
a277d36696 feat: sqs 2023-11-20 17:53:29 -03:00
Davidson Gomes
6c9e86e17a feat: sqs 2023-11-20 17:52:36 -03:00
Davidson Gomes
e75ef21eb6 Merge pull request #216 from craines/main
fix: Removed await from webhook when sending a message
2023-11-18 16:38:32 -03:00
craines
04e5443b82 fix: send reaction 2023-11-15 21:52:56 -03:00
craines
8b4cdf3b9b fix: Removed await from webhook when sending a message 2023-11-14 16:47:25 -03:00
Jean Carlo Nascimento
37f1620f7c Update typebot.service.ts - element.underline change ~ for *
There's no underline in WhatsApp ~ use strikethrough instead, I switched to * bold.
2023-11-12 19:11:47 -03:00
Davidson Gomes
b0a0e805cf Merge pull request #187 from jaison-x/deleting-instances
Deleting instances
2023-11-09 14:41:43 -03:00
Davidson Gomes
c619e253a2 Merge pull request #198 from gabrielpastori1/fix-typebot-error-handle
Handle erros in Typebot
2023-11-09 14:32:30 -03:00
Davidson Gomes
2bd111f1e2 Merge pull request #197 from vitorogen/develop
Handle optional chaining for 'settings.msg_call', this change prevent…
2023-11-05 19:44:27 -03:00
Davidson Gomes
40174b50eb Merge pull request #190 from w3nder/develop
fix: size of group participants
2023-11-05 19:43:45 -03:00
Davidson Gomes
e0fe28717f Merge pull request #186 from jaison-x/adjust-mongo-deletion
-> Adjusting function cleaningStoreFiles to remove itens from missing…
2023-11-05 19:42:24 -03:00
Gabriel Pastori
ac5fc22043 try catch entire sendTypebot 2023-10-30 18:05:18 -03:00
Gabriel Pastori
e30f196dad remove duplicate 2023-10-29 13:22:41 -03:00
Gabriel Pastori
9e4e1ce8ec Merge branch 'fix-typebot-error-handle' of https://github.com/gabrielpastori1/ticketme-evolution-api into fix-typebot-error-handle 2023-10-29 13:01:37 -03:00
Gabriel Pastori
f710898844 fix: in error catch in createNewSession 2023-10-29 12:59:29 -03:00
Gabriel Pastori
94633484ca Merge branch 'develop' into fix-typebot-error-handle 2023-10-29 12:54:05 -03:00
Gabriel Pastori
0817c2589f expand try catch for all function 2023-10-29 12:49:26 -03:00
Gabriel Pastori
8a99386b33 handle erros 2023-10-28 21:21:12 -03:00
Vitor
52d6a563d6 Handle optional chaining for 'settings.msg_call', this change prevents 'TypeError: Cannot read properties of undefined' errors when 'msg_call' is undefined. 2023-10-27 22:49:57 -03:00
Davidson Gomes
d0a5ae1da4 fix: Removed senderKeyDistributionMessage 2023-10-26 18:01:17 -03:00
Davidson Gomes
783c00a1d9 fix: Added mimetype field when sending media 2023-10-25 10:29:24 -03:00
Davidson Gomes
bc70ec8b07 fix: start session 2023-10-25 08:19:44 -03:00
Davidson Gomes
50e1efe5d7 fix: start session 2023-10-25 07:00:58 -03:00
Davidson Gomes
d8629e53f1 fix: start session 2023-10-24 13:16:35 -03:00
Davidson Gomes
cc9df1dabb fix: start session 2023-10-24 12:06:20 -03:00
Davidson Gomes
cd6cb8182e fix: start session 2023-10-24 12:05:58 -03:00
Wender Teixeira
5b0e90e5b9 Update whatsapp.service.ts 2023-10-19 22:41:16 -03:00
jaison-x
3c3bbc84b3 -> When deleting a instance in connecting state, the event remove.instance was not triggered; 2023-10-18 19:52:33 -03:00
Jaison
23615cff4f -> Adjusting function cleaningStoreFiles to remove itens from missing mongo collections;
-> AuthModel was using a wrong filter;
2023-10-18 18:57:11 -03:00
Davidson Gomes
daadc6cb68 fix: adjusts in proxy 2023-10-18 18:09:26 -03:00
Davidson Gomes
e157a2a36b fix: adjusts in proxy 2023-10-18 18:09:01 -03:00
Davidson Gomes
d8d7debfee fix: lid messages 2023-10-11 17:27:49 -03:00
Davidson Gomes
a82b206fe6 test: messages.upsert 2023-10-10 10:00:11 -03:00
Davidson Gomes
a4416214c8 Merge tag '1.5.4' into develop
* Baileys logger typing issue resolved
* Solved problem with duplicate messages in chatwoot
2023-10-09 20:43:50 -03:00
Davidson Gomes
8fe75cd210 Merge branch 'release/1.5.4' 2023-10-09 20:43:40 -03:00
Davidson Gomes
303effebbc version: 1.5.4 2023-10-09 20:43:30 -03:00
Davidson Gomes
f32a34190d fix: adjusts logger 2023-10-09 20:17:01 -03:00
Davidson Gomes
8588ef1d8a fix: adjusts logger 2023-10-09 20:15:53 -03:00
Davidson Gomes
51ec4821f3 fix: adjusts logger 2023-10-09 20:14:50 -03:00
Davidson Gomes
957033a7bb ajustes 2023-10-09 19:57:26 -03:00
Davidson Gomes
62c74deac3 fix: Solved problem with duplicate messages in chatwoot 2023-10-09 18:00:14 -03:00
Davidson Gomes
29fd448998 Merge tag '1.5.3' into develop
* Swagger documentation
* Added base 64 sending option via webhook

* Remove rabbitmq queues when delete instances
* Improvement in restart instance to completely redo the connection
* Update node version: v20
* Correction of messages sent by the api and typebot not appearing in chatwoot
* Adjustment to start typebot, added startSession parameter
* Chatwoot now receives messages sent via api and typebot
* Fixed problem with starting with an input in typebot
* Added check to ensure variables are not empty before executing foreach in start typebot
2023-10-06 18:55:52 -03:00
Davidson Gomes
e55cb08a6a Merge branch 'release/1.5.3' 2023-10-06 18:55:44 -03:00
Davidson Gomes
047359e8dc version: 1.5.3 2023-10-06 18:55:36 -03:00
Davidson Gomes
eb814e181a adjusts in swagger 2023-10-06 18:45:26 -03:00
Davidson Gomes
857031ff5a adjusts in swagger 2023-10-06 18:05:37 -03:00
Davidson Gomes
d5eeb68714 feat: webhook base64 option 2023-10-05 17:05:41 -03:00
Davidson Gomes
966b287026 feat: webhook base64 option 2023-10-05 16:01:47 -03:00
Davidson Gomes
a348729109 Merge branch 'develop' of github.com:EvolutionAPI/evolution-api into develop 2023-10-05 15:59:59 -03:00
Davidson Gomes
1f29b7733e Merge pull request #163 from w3nder/develop
Fix: Variables null
2023-10-05 15:59:39 -03:00
Davidson Gomes
e26ae30f6f feat: webhook base64 option 2023-10-05 15:57:53 -03:00
Davidson Gomes
547943a05c Merge branch 'develop' of github.com:EvolutionAPI/evolution-api into develop 2023-10-05 15:54:53 -03:00
Davidson Gomes
46aa229531 fix: adjusts in swagger 2023-10-05 15:54:46 -03:00
Davidson Gomes
28bd796289 Merge pull request #161 from moraisamilton/develop
Recuperar base64 de media enviada por webhook
2023-10-05 15:54:20 -03:00
Wender Teixeira
6a3f82ed7e Fix: Variables null 2023-10-05 11:43:18 -03:00
Amilton Morais
523f3301c0 Update wa.types.ts
Foi criado novas propriedades para recuperar Base64 da media enviada por webhook.
2023-10-03 17:20:14 -03:00
Amilton Morais
f085343a99 Update whatsapp.service.ts
Foi criado novo código para recuperar Base64 da media enviada por webhook.
2023-10-03 17:18:58 -03:00
Amilton Morais
f76a924700 Update webhook.service.ts
Foi criado novo variavel "webhook_base64:false' para retorno erro.
2023-10-03 17:13:58 -03:00
Amilton Morais
f8e3b76a4a Update webhook.model.ts
Foi criado novas propriedades para recuperar Base64 da media enviada por webhook.
2023-10-03 16:59:06 -03:00
Amilton Morais
b8f1e8a7ef Update instance.dto.ts
Foi criado novas propriedades "webhook_base64?: boolean;" para recuperar Base64 da media enviada por webhook.
2023-10-03 16:56:44 -03:00
Amilton Morais
d007fc49d8 Update instance.controller.ts
Foi criado novas propriedades para recuperar Base64 da media enviada por webhook.
2023-10-03 16:45:05 -03:00
Amilton Morais
f6d8ebd8d3 Update dev-env.yml
Inserido nova variável WEBHOOK_BASE64 para recuperar Base64 da media enviar por webhook.
2023-10-03 16:39:04 -03:00
Davidson Gomes
6ff9c4578a Fixed problem with starting with an input in typebot 2023-10-02 18:23:03 -03:00
Davidson Gomes
33acfe1464 chatwoot now receives messages sent via api and typebot 2023-10-02 17:59:54 -03:00
Davidson Gomes
f5eeb16bb1 Adjustment to start typebot, added startSession parameter 2023-10-02 17:05:22 -03:00
Davidson Gomes
c35c5faaa4 correction of messages sent by the api and typebot not appearing in chatwoot 2023-10-02 16:17:28 -03:00
Davidson Gomes
8425ebc13f Merge pull request #156 from EvolutionAPI/revert-154-evolution-api-1.5.2-develop-francis
Revert "Start Typebot com opção de ativar chatbot ou não"
2023-10-02 16:10:45 -03:00
Davidson Gomes
6fc37a4298 Revert "Start Typebot com opção de ativar chatbot ou não" 2023-10-02 19:10:34 +00:00
Davidson Gomes
99f3e77c12 Merge pull request #154 from francisbreit/evolution-api-1.5.2-develop-francis
Start Typebot com opção de ativar chatbot ou não
2023-10-02 16:10:29 -03:00
Davidson Gomes
a9c087c45f correction of messages sent by the api and typebot not appearing in chatwoot 2023-10-02 16:10:04 -03:00
Francis Breit
3f4333087f Start Typebot com opção de ativar chatbot ou não
Foi criada a variável enabled_typebot (não obrigatória)
enabled_typebot igual a true ou vazio: o comportamento do "startTypebot" atua como a nova funcionalidadede sessões persistentes (v1.5.2) onde o flow do Typebot disparado atua como chatbot.
enabled_typebot igual a false: o comportamento do "startTypebot" atua como era na Evolution v.1.5.1 onde o flow do Typebot disparado atua como mensagem simples, nao ativa o chatbot e funciona apenas como mensagens simples.
Obs1: Se setada como true ou se for omitida essa variável no comando start Typebot, enabled_typebot será assumida como true, ou seja, start typebot aciona o flow com o chatbot ativado, imediatamente após o envio, aguardando interação do contato.. Se, antes do acionamento do start typebot, tiver um outro chatbot ativo, o mesmo será substituído pelo novo, ora enviado.
Obs2: Se setada como false, dispara apenas como notificação e não ativa o bot. se tiver outro bot ativo na instancia o mesmo continuará ativo, após disparada a mensagem
2023-10-02 11:56:24 -03:00
Davidson Gomes
e1ac29683d wip: swagger 2023-10-02 09:24:53 -03:00
Davidson Gomes
5c74cbfe19 improvement in restart instance to completely redo the connection 2023-09-30 16:36:32 -03:00
Davidson Gomes
3fdb3fa673 fix: Remove rabbitmq queues when delete instances 2023-09-30 07:20:57 -03:00
Davidson Gomes
ba584974cb Merge tag '1.5.2' into develop
v
2023-09-28 17:58:59 -03:00
Davidson Gomes
bddd6408ac Merge branch 'release/1.5.2' 2023-09-28 17:58:55 -03:00
Davidson Gomes
413ad66a07 version: 1.5.2 2023-09-28 17:58:37 -03:00
Davidson Gomes
0ef5d884cc version: 1.5.2 2023-09-28 17:56:47 -03:00
Davidson Gomes
f6b6d23e93 Merge pull request #133 from francisbreit/fetch-instances
Correção de nao recebimento de midias armazenadas mo minio/s3 Update whatsapp.service.ts
2023-09-28 17:47:17 -03:00
Davidson Gomes
50be69f3d3 Merge pull request #132 from IsraelXabregas/chatwoot-model-fix-schema-db
Fix chatwootSchema in chatwoot model to store reopen_conversation and conversation_pending options
2023-09-28 17:45:13 -03:00
Davidson Gomes
5a75e4d5e6 Merge pull request #131 from matheuskshn/develop
Melhoria no método "startTypebot" para criar sessão persistente quando acionado
2023-09-28 17:44:00 -03:00
Davidson Gomes
ec463df9d6 Merge pull request #126 from francisbreit/main
Novo manager para Evo 1.5.1 - atualização Set Typebot
2023-09-28 17:42:06 -03:00
Francis Breit
b648334323 Corrigir nao recebimento de midias minio/s3 - finalizado- Update whatsapp.service.tsUpdate whatsapp.service.ts
Correção nao recebimento de midias com urls do minio/s3 .
Urls sem o nome da extensão da midia impediam o envio das mensagens por erro na detecção do mimetype.
Imagem e Video
2023-09-26 14:15:50 -03:00
Francis Breit
916972aeb1 Update whatsapp.service.ts 2023-09-26 13:52:11 -03:00
Francis Breit
3893e01af9 Corrigir nao recebimento de midias minio/s3 Update whatsapp.service.ts
Correção nao recebimento de midias com urls do minio/s3 .
Urls sem o nome da extensão da midia impediam o envio das mensagens por erro na detecção do mimetype.
2023-09-26 13:27:58 -03:00
Israel Xabregas Ramos
7835f32c8b Fix chatwootSchema in chatwoot model to store reopen_conversation and conversation_pending options 2023-09-25 20:45:14 -03:00
Matheus Gomes
37302244ee Update typebot.service.ts 2023-09-25 16:37:43 -03:00
Matheus Gomes
f1be7ddb83 Update typebot.service.ts 2023-09-25 16:22:41 -03:00
Matheus Gomes
7447a65a83 Update typebot.service.ts 2023-09-25 16:05:18 -03:00
Matheus Gomes
129009d602 Update typebot.service.ts 2023-09-25 15:55:12 -03:00
Matheus Gomes
c656bd6f4b Enhancement of Session Initialization in "StartTypebot" Function
Enhanced "StartTypebot" to initialize sessionIDs during the initial interaction, improving user experience on WhatsApp and preventing unexpected bot restarts.
2023-09-25 02:38:37 -03:00
Francis Breit
36528d7484 Inclusão de Listening From Me no est Typebot Update manager.json
Correção e inclusão de Listening From Me
2023-09-22 13:28:29 -03:00
Francis Breit
f9c85b6a67 Novo manager para Evo 1.5.1 - atualização Set Typebot
Incluída a opção da variável listening_from_me do Set Typebot
2023-09-21 10:04:00 -03:00
Davidson Gomes
4dfe6bdbe8 Merge pull request #122 from francisbreit/fetch-instances
Update monitor.service.ts - Evolution ap i 1.5.1 - Problemas ao ler / consultar instancias (FETCH_INSTANCES)
2023-09-20 15:09:28 -03:00
Francis Breit
ee343f2fa1 Update monitor.service.ts
Evolution ap i 1.5.1 - Problemas ao ler / consultar instancias (FETCH_INSTANCES)

Ao consultar instancias as mesmas nao apareciam, seja via manager, seja via postman
2023-09-20 11:13:43 -03:00
Davidson Gomes
1a1f5f85b2 Merge tag '1.5.1' into develop
* Added listening_from_me option in Set Typebot
* Added variables options in Start Typebot
* Added webhooks for typebot events
* Added ChamaAI integration
* Added webhook to send errors
* Added support for messaging with ads on chatwoot

* Fix looping connection messages in chatwoot
* Improved performance of fetch instances
2023-09-17 13:55:02 -03:00
Davidson Gomes
bd64b0c884 Merge branch 'release/1.5.1' 2023-09-17 13:54:49 -03:00
Davidson Gomes
e1c8928ed9 Added support for messaging with ads on chatwoot 2023-09-17 13:52:54 -03:00
Davidson Gomes
1f98940445 Added support for messaging with ads on chatwoot 2023-09-17 13:48:42 -03:00
Davidson Gomes
707aa22a6d Added support for messaging with ads on chatwoot 2023-09-17 13:48:27 -03:00
Davidson Gomes
32da15fa8a Merge branch 'develop' of github.com:EvolutionAPI/evolution-api into develop 2023-09-17 13:35:58 -03:00
Davidson Gomes
97cd6e289a Merge pull request #111 from AdsonCicilioti/ads-preview-1.5.1
Initial support for preview and reference from Ads messages on Chatwoot
2023-09-17 13:35:28 -03:00
Davidson Gomes
def6576fb9 Merge branch 'develop' into ads-preview-1.5.1 2023-09-17 13:35:18 -03:00
Davidson Gomes
196c10b253 Merge pull request #108 from raimartinsb/EvolutionAPI-develop
[Improvement] - Send and Update source_id of messages to chatwoot
2023-09-17 13:32:27 -03:00
AdsonCicilioti
cfdca38d59 add: fixed crop (cover) ads imge thumbnail with Jimp library 2023-09-13 00:04:02 -03:00
AdsonCicilioti
ccd90a69ee add: initial support for preview and reference from messages with Ads metadata 2023-09-12 13:43:17 -03:00
AdsonCicilioti
c16f962d2b chore: compreensive var name for conversation term 2023-09-12 13:39:40 -03:00
Davidson Gomes
8fccf69ceb Merge branch 'develop' of github.com:EvolutionAPI/evolution-api into develop 2023-09-11 09:39:13 -03:00
Davidson Gomes
adc8833670 fix: Debug Bad Request 2023-09-11 09:39:09 -03:00
Davidson Gomes
ecbf90ded8 Merge pull request #99 from moskoweb/bug-bad-request
fix: Debug Bad Request
2023-09-11 09:38:28 -03:00
raimartinsb
c5d2d7782a Merge branch 'develop' of https://github.com/EvolutionAPI/evolution-api into EvolutionAPI-develop 2023-09-11 08:08:18 -03:00
raimartinsb
72dae22ef4 Configuration to update source_id only when desired 2023-09-11 07:44:09 -03:00
Alan Mosko
9a9cd41009 wip 2023-09-06 16:24:13 -03:00
Alan Mosko
0c4c8162c2 wip 2023-09-06 16:18:48 -03:00
Alan Mosko
d47cc5d5f4 wip 2023-09-06 16:11:59 -03:00
raimartinsb
cb942e512d improved message update 2023-09-06 13:28:42 -03:00
raimartinsb
bd0a479645 added source_id in media messages 2023-09-06 09:11:15 -03:00
Davidson Gomes
cd0da914f4 Merge pull request #96 from moskoweb/fetch-profile
Get Info JID Correct
2023-09-05 21:42:21 -03:00
Davidson Gomes
7a7e72897a Merge pull request #95 from w3nder/develop
Melhorando o desempenho no carregamento da instância.
2023-09-05 21:41:29 -03:00
Alan Mosko
c1542054c9 Merge branch 'develop' into fetch-profile 2023-09-05 17:47:41 -03:00
Alan Mosko
250e67e7ae Update whatsapp.service.ts 2023-09-05 17:44:47 -03:00
Wender Teixeira
cdbe839b35 Update monitor.service.ts 2023-09-05 11:49:02 -03:00
Wender Teixeira
240a77dcce Update monitor.service.ts
Fix monitor
2023-09-05 11:48:38 -03:00
Wender Teixeira
1dc5bb8bd1 Update monitor.service.ts 2023-09-05 11:47:24 -03:00
Davidson Gomes
23534da27d fix: added delay in chatwoot receive webhook 2023-09-05 08:39:51 -03:00
Wender Teixeira
8652d4031c Update monitor.service.ts 2023-09-04 19:00:42 -03:00
Davidson Gomes
384e311c7a fix: added delay in chatwoot receive webhook 2023-09-04 16:48:04 -03:00
Davidson Gomes
2791f88b4c fix: added delay in chatwoot receive webhook 2023-09-04 16:13:43 -03:00
Wender Teixeira
402d5af19a Update monitor.service.ts 2023-09-04 15:18:32 -03:00
Wender Teixeira
b554d8c19c Update monitor.service.ts (loadInstances)
Melhorando é organizando o loadInstances
2023-09-04 15:11:23 -03:00
Wender Teixeira
7d9dd64303 Update monitor.service.ts
Isso permite que as operações assíncronas sejam executadas em paralelo
2023-09-04 15:06:18 -03:00
Davidson Gomes
41bea8931f test: process exit when errors 2023-09-04 13:08:16 -03:00
Davidson Gomes
f83d8de476 test: process exit when errors 2023-09-04 13:00:16 -03:00
Davidson Gomes
af2a652098 Merge pull request #90 from moskoweb/patch-6
fix: Group Create
2023-09-01 07:02:10 -03:00
Davidson Gomes
a3c911263d Merge pull request #92 from francisbreit/main
fix: Update manager.json
2023-09-01 06:52:02 -03:00
Davidson Gomes
836c677837 Merge branch 'develop' into main 2023-09-01 06:51:40 -03:00
Davidson Gomes
7e4dbfdd7e fix: Added log when send event to rabbitMQ and Websocket 2023-08-31 18:24:30 -03:00
Davidson Gomes
6eda556242 fix: create rabbitmq queues on set config 2023-08-31 17:10:19 -03:00
Davidson Gomes
3ea454c7ed fix: create rabbitmq queues on set config 2023-08-31 17:01:09 -03:00
Davidson Gomes
9123d7014d fix: create rabbitmq queues on set config 2023-08-31 16:49:50 -03:00
Francis Breit
3ea3abe81a Update manager.json
- Added the following settings for instances: Set Typebot and Typebot Change Session Status.
- Fixed bug in Webhook settings
2023-08-31 07:55:53 -03:00
raimartinsb
7289c3d7f9 Add source_id and update message 2023-08-31 07:52:36 -03:00
Alan Mosko
d00e1df29c [Melhoria] Group Create
Verifica todos os participantes e pega apenas os que existe no WhatsApp
2023-08-30 15:09:03 -03:00
Davidson Gomes
16a18c4f22 fix: update error.config.ts 2023-08-30 13:27:47 -03:00
Davidson Gomes
30b156d92f Merge pull request #89 from w3nder/develop
Update error.config.ts
2023-08-30 13:25:22 -03:00
Davidson Gomes
931f9d33e4 Merge pull request #87 from moskoweb/phone-name
fix: navigator client name
2023-08-30 13:24:40 -03:00
Wender Teixeira
e61fe4d092 Update error.config.ts
encerramento controlado para lidar com erros não capturados no aplicativo.
2023-08-30 12:38:53 -03:00
Davidson Gomes
5bc33ac654 Merge pull request #88 from moskoweb/patch-5
Correção de Erro
2023-08-29 21:00:41 -03:00
Alan Mosko
878ba5a869 Correção de Erro
```This comparison appears to be unintentional because the types 'string' and 'number' have no overlap.```
2023-08-29 18:57:31 -03:00
Alan Mosko
92632b2b96 wip 2023-08-29 14:29:50 -03:00
Davidson Gomes
d803a9e298 Merge pull request #85 from w3nder/develop
Fix set event rabbitmq/websocket
2023-08-29 11:29:14 -03:00
Davidson Gomes
b9f67533dd Merge pull request #83 from moskoweb/patch-4
fix: DEL_INSTANCE
2023-08-29 11:27:57 -03:00
Davidson Gomes
7ade78bedf Merge pull request #78 from AdsonCicilioti/docker-net-declaration
clean: docker network declaration and build of the `evolution/api` image
2023-08-29 11:27:10 -03:00
Davidson Gomes
b4eca48f4d Merge pull request #59 from unilogica/main
Bugfix Internal Error 500: fetchInstances (apikey not found)
2023-08-29 11:24:03 -03:00
Davidson Gomes
2cf8e317fa Merge pull request #57 from helioelias/main
Fix: For webhook to work with localhost
2023-08-29 11:15:08 -03:00
Wender Teixeira
821a422ab5 Fix set event rabbitmq/websocket 2023-08-28 23:26:40 -03:00
Alan Mosko
91c7b4f2cd Correção DEL_INSTANCE 2023-08-28 09:59:04 -03:00
AdsonCicilioti
adb43ec5b3 clean: correct docker network declaration 2023-08-26 02:53:02 -03:00
AdsonCicilioti
c9721d7bc9 clean: docker build will be remove in future releases / build into compose file 2023-08-26 02:36:45 -03:00
AdsonCicilioti
bbc2b8a396 clean: declarative bridge network instead shellscript check 2023-08-26 00:29:58 -03:00
Davidson Gomes
54cfa67d52 Added webhook to send errors 2023-08-25 09:31:13 -03:00
Davidson Gomes
9b72b3e332 Added webhook to send errors 2023-08-25 09:01:48 -03:00
Davidson Gomes
c03919be2d Added ChamaAI integration 2023-08-23 08:58:49 -03:00
Davidson Gomes
706cc6f49c Added webhooks for typebot events 2023-08-23 08:15:53 -03:00
Davidson Gomes
10c7e81e02 Added webhooks for typebot events 2023-08-23 07:54:46 -03:00
Davidson Gomes
03637b2d4d Added listening_from_me option in Set Typebot 2023-08-23 07:27:40 -03:00
Davidson Gomes
b7218a05be feat: Inegration with Chama AI 2023-08-19 15:13:35 -03:00
Davidson Gomes
a2cd57d9c6 feat: Inegration with Chama AI 2023-08-19 10:42:41 -03:00
Unilógica
001849eeaa Merge branch 'EvolutionAPI:main' into main 2023-08-18 18:02:53 -03:00
Davidson Gomes
bf09a70096 Merge tag '1.5.0' into develop
* New instance manager in /manager route
* Added extra files for chatwoot and appsmith
* Added Get Last Message and Archive for Chat
* Added env var QRCODE_COLOR
* Added websocket to send events
* Added rabbitmq to send events
* Added Typebot integration
* Added proxy endpoint
* Added send and date_time in webhook data

* Solved problem when disconnecting from the instance the instance was deleted
* Encoded spaces in chatwoot webhook
* Adjustment in the saving of contacts, saving the information of the number and Jid
* Update Dockerfile
* If you pass empty events in create instance and set webhook it is understood as all
* Fixed issue that did not output base64 averages
* Messages sent by the api now arrive in chatwoot

- Chatwoot: v2.18.0 - v3.0.0
- Typebot: v2.16.0
- Manager Evolution API
2023-08-18 12:49:12 -03:00
Davidson Gomes
530aec92a9 Merge branch 'release/1.5.0' 2023-08-18 12:48:53 -03:00
Davidson Gomes
deb8f2a0b7 Added send and date_time in webhook data 2023-08-18 12:48:30 -03:00
Davidson Gomes
5c247e3d2c Added send and date_time in webhook data 2023-08-18 12:46:47 -03:00
Davidson Gomes
04b9a070c4 Added send and date_time in webhook data 2023-08-18 12:46:46 -03:00
Davidson Gomes
dd2caf720c Added Typebot integration 2023-08-18 12:24:05 -03:00
Davidson Gomes
0d16a7aab0 Added Typebot integration 2023-08-18 11:59:04 -03:00
Davidson Gomes
31325d0999 Added Typebot integration 2023-08-18 11:58:41 -03:00
Davidson Gomes
6f99784224 Added Typebot integration 2023-08-18 11:38:50 -03:00
Davidson Gomes
201e6f7e7b Added rabbitmq to send events 2023-08-18 10:38:32 -03:00
Davidson Gomes
c4d41134b8 Messages sent by the api now arrive in chatwoot 2023-08-18 09:33:17 -03:00
Davidson Gomes
680c92ecec Messages sent by the api now arrive in chatwoot 2023-08-18 09:25:34 -03:00
Davidson Gomes
deb07d2b7f Messages sent by the api now arrive in chatwoot 2023-08-18 08:44:13 -03:00
Davidson Gomes
3a14fc373a adjust params rabbitmq 2023-08-17 18:19:46 -03:00
Allyson de Paula
29e429a02e Merge branch 'main' of https://github.com/unilogica/evolution-api 2023-08-17 13:07:05 -03:00
Allyson de Paula
907a0ee135 Proxy test 2023-08-12 15:05:10 -03:00
Unilógica
22a03f77ab Merge pull request #1 from unilogica/develop
Develop
2023-08-12 15:01:54 -03:00
Unilógica
9761b10bf6 Merge branch 'EvolutionAPI:develop' into develop 2023-08-12 12:41:15 -03:00
Davidson Gomes
c364d3fdca feat: Added Typebot integration 2023-08-11 20:49:39 -03:00
Davidson Gomes
07ad5756eb fix: Fixed issue that did not output base64 averages 2023-08-09 16:57:23 -03:00
Allyson de Paula
6e401eecde Bugfix Internal Error 500: fetchInstances (apikey not found) 2023-08-09 16:56:38 -03:00
Helio Elias
f32e259d2f Fix isURL function to by pass url with localhost, when webhook is enable 2023-08-08 21:06:58 -03:00
Helio Elias
83ed0e6454 Merge branch 'EvolutionAPI:main' into main 2023-08-08 21:02:19 -03:00
Davidson Gomes
da568e4ea5 feat: Added version in logs 2023-08-07 19:46:34 -03:00
Davidson Gomes
ad819bf3ba feat: Added Typebot integration 2023-08-07 19:03:15 -03:00
Davidson Gomes
b502ebd23a feat: Added Typebot integration 2023-08-07 18:54:12 -03:00
Davidson Gomes
7c5d94c19e feat: Added Typebot integration 2023-08-07 15:43:57 -03:00
Davidson Gomes
a16b5f4644 feat: added proxy endpoint 2023-08-07 12:10:53 -03:00
Davidson Gomes
f3cb8c531b feat: added proxy endpoint 2023-08-07 12:10:33 -03:00
Davidson Gomes
469e696ab7 Added Typebot integration 2023-08-04 16:15:59 -03:00
Davidson Gomes
d99ccd9df6 Added Typebot integration 2023-08-04 15:03:08 -03:00
Davidson Gomes
3b3118d764 Added Typebot integration 2023-08-04 15:00:55 -03:00
Davidson Gomes
84386847e2 readme buy me coffe 2023-08-03 07:32:29 -03:00
Davidson Gomes
0da3d100b3 feat: Added rabbitmq to send events 2023-08-02 21:33:59 -03:00
Davidson Gomes
56d621bab8 feat: Added rabbitmq to send events 2023-08-02 21:14:21 -03:00
Davidson Gomes
f1571b5f66 feat: Added rabbitmq to send events 2023-08-02 17:41:15 -03:00
Davidson Gomes
55f8e179af feat: Added rabbitmq to send events 2023-08-02 17:39:07 -03:00
Davidson Gomes
ab5289a136 feat: Added rabbitmq to send events 2023-08-02 17:29:09 -03:00
Davidson Gomes
e05c48979d feat: Added rabbitmq to send events 2023-08-02 17:28:52 -03:00
Davidson Gomes
24c880343b feat: Added websocket with lib socket.io 2023-08-02 16:11:19 -03:00
Davidson Gomes
b3b4ee7a28 fix: If you pass empty events in create instance and set webhook it is understood as all 2023-08-02 14:48:02 -03:00
Helio Elias
e26b440a66 Merge pull request #1 from helioelias/fix/dockers
Fix/dockers
2023-08-02 13:29:13 -03:00
Helio Elias
d6194316e1 Fix Dockers 2023-08-02 13:25:00 -03:00
Davidson Gomes
341148612f feat: Added websocket with lib socket.io 2023-08-02 13:21:15 -03:00
Davidson Gomes
79864e97d6 feat: Added websocket with lib socket.io 2023-08-02 13:08:30 -03:00
Davidson Gomes
ed5e66e430 fix: Update view manager 2023-08-01 18:01:29 -03:00
Davidson Gomes
074a861fb4 fix: Update Dockerfile 2023-07-31 16:02:40 -03:00
Davidson Gomes
b88656829e feat: Added env var QRCODE_COLOR 2023-07-31 15:51:05 -03:00
Davidson Gomes
aefe6a5943 feat: Added Get Last Message and Archive for Chat 2023-07-31 15:30:48 -03:00
Davidson Gomes
3d743f8498 Merge branch 'develop' of github.com:EvolutionAPI/evolution-api into develop 2023-07-31 15:30:33 -03:00
Davidson Gomes
0186fff67d feat: Added Get Last Message and Archive for Chat
Added Get Last Message and Archive for Chat
2023-07-31 15:30:26 -03:00
Davidson Gomes
38f61cdf75 fix: Update Dockerfile 2023-07-31 15:28:00 -03:00
Davidson Gomes
84366002db fix: Update Dockerfile 2023-07-31 15:27:47 -03:00
Davidson Gomes
eff5bb74b5 Merge pull request #50 from EvolutionAPI/revert-43-docker
Revert "Update Dockerfile"
2023-07-31 15:26:00 -03:00
Davidson Gomes
2614088fae Revert "Update Dockerfile" 2023-07-31 15:25:48 -03:00
Davidson Gomes
3699e04db9 Merge pull request #43 from moskoweb/docker
Update Dockerfile
2023-07-31 15:25:09 -03:00
Davidson Gomes
0dca009c01 fix: Adjustment in the saving of contacts, saving the information of the number and Jid 2023-07-31 13:42:37 -03:00
Davidson Gomes
1b39eb1a23 add: Added extra files for chatwoot and appsmith 2023-07-31 13:13:41 -03:00
Davidson Gomes
2637aebb7f fix: Encoded spaces in chatwoot webhook 2023-07-31 12:34:01 -03:00
Davidson Gomes
8afcfde078 add: Added extra files for chatwoot and appsmith 2023-07-31 12:26:50 -03:00
Davidson Gomes
9ea1eaf3ed fix: Encoded spaces in chatwoot webhook 2023-07-31 10:55:24 -03:00
Davidson Gomes
66d06afaf7 feat: New instance manager in /manager route 2023-07-30 11:03:12 -03:00
Davidson Gomes
cffcca9722 fix: adjust in instance name in chatwoot 2023-07-29 11:30:37 -03:00
Davidson Gomes
fe2b9774d8 fix: Solved problem when disconnecting from the instance the instance was deleted 2023-07-29 11:09:56 -03:00
Alan Mosko
3d02fabef4 Update Dockerfile 2023-07-27 10:47:26 -03:00
Davidson Gomes
f89c2b1f63 Merge tag '1.4.8' into develop
* Fixed error return bug
2023-07-27 10:28:47 -03:00
Davidson Gomes
ee755d5a6c Merge branch 'release/1.4.8' 2023-07-27 10:28:40 -03:00
Davidson Gomes
65e2ecf88e version: 1.4.8 2023-07-27 10:28:26 -03:00
Davidson Gomes
332ec69ee8 fix: Adjusts in return errors 2023-07-27 10:27:41 -03:00
Alan Mosko
1ce30f8431 Update whatsapp.service.ts 2023-07-27 10:20:18 -03:00
Alan Mosko
3ae6944307 Update whatsapp.service.ts 2023-07-27 09:24:38 -03:00
Alan Mosko
52533d4b38 Adição de Get Last Message e Archive por Chat 2023-07-27 09:23:44 -03:00
Davidson Gomes
38409d9336 Merge tag '1.4.7' into develop
* Fixed error return bug
* Fixed problem of getting message when deleting message in chatwoot
* Change in error return pattern
2023-07-27 08:53:02 -03:00
Helio Elias
04a6f7c954 fix docker and create docker-compose with all services 2023-07-21 15:02:09 +00:00
121 changed files with 10238 additions and 792 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -0,0 +1,38 @@
---
name: "[EN] Bug report"
about: Create a report to help us improve
title: "[EN][BUG]"
labels: bug
assignees: ''
---
### Title: [Brief Description of the Bug]
#### Description:
Describe in detail the problem you encountered. Include any relevant context that may help understand the origin of the bug.
#### Steps to Reproduce:
1. List the steps necessary to reproduce the problem.
2. Try to be as specific as possible.
3. If the problem occurs in a specific scenario, describe it here.
#### Expected Behavior:
Describe what you expected to happen when following the steps above.
#### Current Behavior:
Explain what actually happens when you follow the steps above.
#### Screenshots/Videos:
If possible, add screenshots or videos illustrating the problem. This can be extremely helpful in understanding the issue.
#### Environment:
- **Server:** [e.g., Ubuntu 18.04]
- **API Version:** [e.g., 1.5.4]
- **Other Hardware/Software Specifications:** [e.g., CPU, GPU]
#### Submitting Logs:
Please attach logs that may be related to the problem. If the logs contain sensitive information, consider sending them privately to one of the project maintainers.
#### Additional Notes:
Include here any other information that you think might be useful in understanding or resolving the bug.

View File

@@ -0,0 +1,28 @@
---
name: "[EN] Feature request"
about: Suggest an idea for the API
title: "[EN][FEAT]"
labels: enhancement
assignees: ''
---
### Title: [Brief Description of Feature Request]
#### Detailed Description:
Clearly and in detail, describe the functionality you wish to be implemented. Explain how this fits into the context of the project.
#### Rationale:
Explain why this functionality would be useful for the project. This helps in understanding the importance and priority of the request.
#### Usage Examples:
Provide specific examples of how this feature could be used. This can include scenarios or use cases where the feature would be particularly beneficial.
#### Possible Implementations:
If you have ideas on how this feature might be implemented, please share them here. This is not mandatory but can be helpful for the development team.
#### Impact on the Project:
Discuss how this new feature could impact other parts of the project, if applicable.
#### Additional Notes:
Any other information you believe is relevant to your request.

View File

@@ -0,0 +1,38 @@
---
name: "[PT] Reportar bug"
about: Reportar um problema
title: "[PT][BUG]"
labels: bug
assignees: ''
---
### Título: [Breve Descrição do Bug]
#### Descrição:
Descreva detalhadamente o problema que você encontrou. Inclua qualquer contexto relevante que possa ajudar a entender a origem do bug.
#### Passos para Reproduzir:
1. Liste os passos necessários para reproduzir o problema.
2. Tente ser o mais específico possível.
3. Se o problema ocorrer em um cenário específico, descreva-o aqui.
#### Comportamento Esperado:
Descreva o que você esperava que acontecesse quando seguisse os passos acima.
#### Comportamento Atual:
Explique o que realmente acontece quando você segue os passos acima.
#### Capturas de Tela/Vídeos:
Se possível, adicione capturas de tela ou vídeos que ilustrem o problema. Isso pode ser extremamente útil para entender o problema.
#### Ambiente:
- **Servidor:** [ex: Ubuntu 18.04]
- **Versão da API:** [ex: 1.5.4]
- **Outras Especificações de Hardware/Software:** [ex: CPU, GPU]
#### Envio de Logs:
Por favor, anexe os logs que possam estar relacionados ao problema. Se os logs contiverem informações sensíveis, considere enviá-los de forma privada para um dos mantenedores do projeto.
#### Notas Adicionais:
Inclua aqui qualquer outra informação que você ache que possa ser útil para entender ou resolver o bug.

View File

@@ -0,0 +1,28 @@
---
name: "[PT] Solicitar recurso"
about: Sugira novos recursos para a API
title: "[PT][FEAT]"
labels: enhancement
assignees: ''
---
### Título: [Breve Descrição da Solicitação de Recurso]
#### Descrição Detalhada:
Descreva claramente e em detalhes a funcionalidade que você deseja que seja implementada. Explique como isso se encaixa no contexto do projeto.
#### Racional:
Explique por que essa funcionalidade seria útil para o projeto. Isso ajuda a entender a importância e a prioridade da solicitação.
#### Exemplos de Uso:
Forneça exemplos específicos de como essa funcionalidade poderia ser utilizada. Isso pode incluir cenários ou casos de uso onde a funcionalidade seria particularmente benéfica.
#### Possíveis Implementações:
Se você tem ideias sobre como essa funcionalidade pode ser implementada, por favor, compartilhe-as aqui. Isso não é obrigatório, mas pode ser útil para a equipe de desenvolvimento.
#### Impacto no Projeto:
Discuta como essa nova funcionalidade poderia impactar outras partes do projeto, se aplicável.
#### Notas Adicionais:
Qualquer outra informação que você acredita ser relevante para a sua solicitação.

1
.gitignore vendored
View File

@@ -39,6 +39,7 @@ docker-compose.yaml
/test/
/src/env.yml
/store
*.env
/temp/*

View File

@@ -5,7 +5,9 @@
"editor.smoothScrolling": true,
"editor.tabSize": 2,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true,
"source.fixAll": true
}
"source.fixAll.eslint": "explicit",
"source.fixAll": "explicit"
},
"prisma-smart-formatter.typescript.defaultFormatter": "esbenp.prettier-vscode",
"prisma-smart-formatter.prisma.defaultFormatter": "Prisma.prisma"
}

View File

@@ -1,3 +1,144 @@
# 1.6.1 (2023-12-22 11:43)
### Fixed
* Fixed Lid Messages
* Fixed sending variables to typebot
* Fixed sending variables from typebot
* Correction sending s3/minio media to chatwoot and typebot
* Fixed the problem with typebot closing at the end of the flow, now this is optional with the TYPEBOT_KEEP_OPEN variable
* Fixed chatwoot Bold, Italic and Underline formatting using Regex
* Added the sign_delimiter property to the Chatwoot configuration, allowing you to set a different delimiter for the signature. Default when not defined \n
* Include instance Id field in the instance configuration
* Fixed the pairing code
* Adjusts in typebot
* Fix the problem when disconnecting the instance and connecting again using mongodb
* Options to disable docs and manager
* When deleting a message in whatsapp, delete the message in chatwoot too
# 1.6.0 (2023-12-12 17:24)
### Feature
* Added AWS SQS Integration
* Added support for new typebot API
* Added endpoint sendPresence
* New Instance Manager
* Added auto_create to the chatwoot set to create the inbox automatically or not
* Added reply, delete and message reaction in chatwoot v3.3.1
### Fixed
* Adjusts in proxy
* Adjusts in start session for Typebot
* Added mimetype field when sending media
* Ajusts in validations to messages.upsert
* Fixed messages not received: error handling when updating contact in chatwoot
* Fix workaround to manage param data as an array in mongodb
* Removed await from webhook when sending a message
* Update typebot.service.ts - element.underline change ~ for *
* Removed api restart on receiving an error
* Fixes in mongodb and chatwoot
* Adjusted return from queries in mongodb
* Added restart instance when update profile picture
* Correction of chatwoot functioning with admin flows
* Fixed problem that did not generate qrcode with the chatwoot_conversation_pending option enabled
* Fixed issue where CSAT opened a new ticket when reopen_conversation was disabled
* Fixed issue sending contact to Chatwoot via iOS
### Integrations
* Chatwoot: v3.3.1
* Typebot: v2.20.0
# 1.5.4 (2023-10-09 20:43)
### Fixed
* Baileys logger typing issue resolved
* Solved problem with duplicate messages in chatwoot
# 1.5.3 (2023-10-06 18:55)
### Feature
* Swagger documentation
* Added base 64 sending option via webhook
### Fixed
* Remove rabbitmq queues when delete instances
* Improvement in restart instance to completely redo the connection
* Update node version: v20
* Correction of messages sent by the api and typebot not appearing in chatwoot
* Adjustment to start typebot, added startSession parameter
* Chatwoot now receives messages sent via api and typebot
* Fixed problem with starting with an input in typebot
* Added check to ensure variables are not empty before executing foreach in start typebot
# 1.5.2 (2023-09-28 17:56)
### Fixed
* Fix chatwootSchema in chatwoot model to store reopen_conversation and conversation_pending options
* Problem resolved when sending files from minio to typebot
* Improvement in the "startTypebot" method to create persistent session when triggered
* New manager for Evo 1.5.2 - Set Typebot update
* Resolved problems when reading/querying instances
# 1.5.1 (2023-09-17 13:50)
### Feature
* Added listening_from_me option in Set Typebot
* Added variables options in Start Typebot
* Added webhooks for typebot events
* Added ChamaAI integration
* Added webhook to send errors
* Added support for messaging with ads on chatwoot
### Fixed
* Fix looping connection messages in chatwoot
* Improved performance of fetch instances
# 1.5.0 (2023-08-18 12:47)
### Feature
* New instance manager in /manager route
* Added extra files for chatwoot and appsmith
* Added Get Last Message and Archive for Chat
* Added env var QRCODE_COLOR
* Added websocket to send events
* Added rabbitmq to send events
* Added Typebot integration
* Added proxy endpoint
* Added send and date_time in webhook data
### Fixed
* Solved problem when disconnecting from the instance the instance was deleted
* Encoded spaces in chatwoot webhook
* Adjustment in the saving of contacts, saving the information of the number and Jid
* Update Dockerfile
* If you pass empty events in create instance and set webhook it is understood as all
* Fixed issue that did not output base64 averages
* Messages sent by the api now arrive in chatwoot
### Integrations
* Chatwoot: v2.18.0 - v3.0.0
* Typebot: v2.16.0
* Manager Evolution API
# 1.4.8 (2023-07-27 10:27)
### Fixed
* Fixed error return bug
# 1.4.7 (2023-07-27 08:47)
### Fixed
@@ -43,7 +184,7 @@
### Fixed
* Fixed validation is set settings
* Fixed validation is set settings
* Adjusts in group validations
* Ajusts in sticker message to chatwoot
@@ -78,7 +219,7 @@
### Integrations
- Chatwoot: v2.18.0 - v3.0.0 (Beta)
* Chatwoot: v2.18.0 - v3.0.0 (Beta)
# 1.3.2 (2023-07-21 17:19)
@@ -94,7 +235,7 @@
### Integrations
- Chatwoot: v2.18.0
* Chatwoot: v2.18.0
# 1.3.1 (2023-07-20 07:48)
@@ -104,7 +245,7 @@
### Integrations
- Chatwoot: v2.18.0
* Chatwoot: v2.18.0
# 1.3.0 (2023-07-19 11:33)
@@ -120,7 +261,7 @@
* Translation set to default (english) in chatwoot
### Fixed
* Fixed error to send message in large groups
* Docker files adjusted
* Fixed in the postman collection the webhookByEvent parameter by webhook_by_events
@@ -141,7 +282,7 @@
### Integrations
- Chatwoot: v2.18.0
* Chatwoot: v2.18.0
# 1.2.2 (2023-07-15 09:36)
@@ -152,7 +293,7 @@
### Integrations
- Chatwoot: v2.18.0
* Chatwoot: v2.18.0
# 1.2.1 (2023-07-14 19:04)
@@ -308,4 +449,4 @@
* Sending the local webhook url as destination in the webhook data for webhook redirection
* Startup modes, server or container
* Server Mode works normally as everyone is used to
* Container mode made to use one instance per container, when starting the application an instance is already created and the qrcode is generated and it starts sending webhook without having to call it manually, it only allows one instance at a time.
* Container mode made to use one instance per container, when starting the application an instance is already created and the qrcode is generated and it starts sending webhook without having to call it manually, it only allows one instance at a time.

View File

@@ -31,7 +31,7 @@ CLEAN_STORE_CONTACTS=true
CLEAN_STORE_CHATS=true
# Permanent data storage
DATABASE_ENABLED=true
DATABASE_ENABLED=false
DATABASE_CONNECTION_URI=mongodb://root:root@mongodb:27017/?authSource=admin&readPreference=primary&ssl=false&directConnection=true
DATABASE_CONNECTION_DB_PREFIX_NAME=evdocker
@@ -42,10 +42,21 @@ DATABASE_SAVE_MESSAGE_UPDATE=false
DATABASE_SAVE_DATA_CONTACTS=false
DATABASE_SAVE_DATA_CHATS=false
REDIS_ENABLED=true
REDIS_ENABLED=false
REDIS_URI=redis://redis:6379
REDIS_PREFIX_KEY=evdocker
RABBITMQ_ENABLED=false
RABBITMQ_URI=amqp://guest:guest@rabbitmq:5672
WEBSOCKET_ENABLED=false
SQS_ENABLED=false
SQS_ACCESS_KEY_ID=
SQS_SECRET_ACCESS_KEY=
SQS_ACCOUNT_ID=
SQS_REGION=
# Global Webhook Settings
# Each instance's Webhook URL and events will be requested at the time it is created
## Define a global webhook that will listen for enabled events from all instances
@@ -76,14 +87,27 @@ WEBHOOK_EVENTS_CONNECTION_UPDATE=true
WEBHOOK_EVENTS_CALL=true
# This event fires every time a new token is requested via the refresh route
WEBHOOK_EVENTS_NEW_JWT_TOKEN=false
# This events is used with Typebot
WEBHOOK_EVENTS_TYPEBOT_START=false
WEBHOOK_EVENTS_TYPEBOT_CHANGE_STATUS=false
# This event is used with Chama AI
WEBHOOK_EVENTS_CHAMA_AI_ACTION=false
# This event is used to send errors
WEBHOOK_EVENTS_ERRORS=false
WEBHOOK_EVENTS_ERRORS_WEBHOOK=
# Name that will be displayed on smartphone connection
CONFIG_SESSION_PHONE_CLIENT=EvolutionAPI
# Browser Name = chrome | firefox | edge | opera | safari
CONFIG_SESSION_PHONE_NAME=chrome
# Browser Name = Chrome | Firefox | Edge | Opera | Safari
CONFIG_SESSION_PHONE_NAME=Chrome
# Set qrcode display limit
QRCODE_LIMIT=30
QRCODE_COLOR=#198754
# old | latest
TYPEBOT_API_VERSION=latest
TYPEBOT_KEEP_OPEN=false
# Defines an authentication type for the api
# We recommend using the apikey because it will allow you to use a custom token,

View File

@@ -0,0 +1,22 @@
version: '3.3'
services:
api:
container_name: evolution_api
image: davidsongomes/evolution-api
restart: always
ports:
- 8080:8080
volumes:
- evolution_instances:/evolution/instances
- evolution_store:/evolution/store
env_file:
- .env
command: ['node', './dist/src/main.js']
expose:
- 8080
volumes:
evolution_instances:
evolution_store:

View File

@@ -0,0 +1,109 @@
# Server URL - Set your application url
SERVER_URL='http://localhost:8080'
# Cors - * for all or set separate by commas - ex.: 'yourdomain1.com, yourdomain2.com'
CORS_ORIGIN='*'
CORS_METHODS='POST,GET,PUT,DELETE'
CORS_CREDENTIALS=true
# Determine the logs to be displayed
LOG_LEVEL='ERROR,WARN,DEBUG,INFO,LOG,VERBOSE,DARK,WEBHOOKS'
LOG_COLOR=true
# Log Baileys - "fatal" | "error" | "warn" | "info" | "debug" | "trace"
LOG_BAILEYS=error
# Determine how long the instance should be deleted from memory in case of no connection.
# Default time: 5 minutes
# If you don't even want an expiration, enter the value false
DEL_INSTANCE=false
# Temporary data storage
STORE_MESSAGES=true
STORE_MESSAGE_UP=true
STORE_CONTACTS=true
STORE_CHATS=true
# Set Store Interval in Seconds (7200 = 2h)
CLEAN_STORE_CLEANING_INTERVAL=7200
CLEAN_STORE_MESSAGES=true
CLEAN_STORE_MESSAGE_UP=true
CLEAN_STORE_CONTACTS=true
CLEAN_STORE_CHATS=true
# Permanent data storage
DATABASE_ENABLED=true
DATABASE_CONNECTION_URI=mongodb://root:root@mongodb:27017/?authSource=admin&readPreference=primary&ssl=false&directConnection=true
DATABASE_CONNECTION_DB_PREFIX_NAME=evolution
# Choose the data you want to save in the application's database or store
DATABASE_SAVE_DATA_INSTANCE=false
DATABASE_SAVE_DATA_NEW_MESSAGE=false
DATABASE_SAVE_MESSAGE_UPDATE=false
DATABASE_SAVE_DATA_CONTACTS=false
DATABASE_SAVE_DATA_CHATS=false
REDIS_ENABLED=true
REDIS_URI=redis://redis:6379
REDIS_PREFIX_KEY=evolution
# Global Webhook Settings
# Each instance's Webhook URL and events will be requested at the time it is created
## Define a global webhook that will listen for enabled events from all instances
WEBHOOK_GLOBAL_URL=''
WEBHOOK_GLOBAL_ENABLED=false
# With this option activated, you work with a url per webhook event, respecting the global url and the name of each event
WEBHOOK_GLOBAL_WEBHOOK_BY_EVENTS=false
## Set the events you want to hear
WEBHOOK_EVENTS_APPLICATION_STARTUP=false
WEBHOOK_EVENTS_QRCODE_UPDATED=true
WEBHOOK_EVENTS_MESSAGES_SET=true
WEBHOOK_EVENTS_MESSAGES_UPSERT=true
WEBHOOK_EVENTS_MESSAGES_UPDATE=true
WEBHOOK_EVENTS_MESSAGES_DELETE=true
WEBHOOK_EVENTS_SEND_MESSAGE=true
WEBHOOK_EVENTS_CONTACTS_SET=true
WEBHOOK_EVENTS_CONTACTS_UPSERT=true
WEBHOOK_EVENTS_CONTACTS_UPDATE=true
WEBHOOK_EVENTS_PRESENCE_UPDATE=true
WEBHOOK_EVENTS_CHATS_SET=true
WEBHOOK_EVENTS_CHATS_UPSERT=true
WEBHOOK_EVENTS_CHATS_UPDATE=true
WEBHOOK_EVENTS_CHATS_DELETE=true
WEBHOOK_EVENTS_GROUPS_UPSERT=true
WEBHOOK_EVENTS_GROUPS_UPDATE=true
WEBHOOK_EVENTS_GROUP_PARTICIPANTS_UPDATE=true
WEBHOOK_EVENTS_CONNECTION_UPDATE=true
# This event fires every time a new token is requested via the refresh route
WEBHOOK_EVENTS_NEW_JWT_TOKEN=false
# Name that will be displayed on smartphone connection
CONFIG_SESSION_PHONE_CLIENT='Evolution API'
# Browser Name = chrome | firefox | edge | opera | safari
CONFIG_SESSION_PHONE_NAME=chrome
# Set qrcode display limit
QRCODE_LIMIT=30
# Defines an authentication type for the api
# We recommend using the apikey because it will allow you to use a custom token,
# if you use jwt, a random token will be generated and may be expired and you will have to generate a new token
# jwt or 'apikey'
AUTHENTICATION_TYPE='apikey'
## Define a global apikey to access all instances.
### OBS: This key must be inserted in the request header to create an instance.
AUTHENTICATION_API_KEY='B6D711FCDE4D4FD5936544120E713976'
AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES=true
## Set the secret key to encrypt and decrypt your token and its expiration time
# seconds - 3600s ===1h | zero (0) - never expires
AUTHENTICATION_JWT_EXPIRIN_IN=0
AUTHENTICATION_JWT_SECRET='L0YWtjb2w554WFqPG'
# Set the instance name and webhook url to create an instance in init the application
# With this option activated, you work with a url per webhook event, respecting the local url and the name of each event
# container or server
AUTHENTICATION_INSTANCE_MODE=server
# if you are using container mode, set the container name and the webhook url to default instance
AUTHENTICATION_INSTANCE_NAME=evolution
AUTHENTICATION_INSTANCE_WEBHOOK_URL=''
AUTHENTICATION_INSTANCE_CHATWOOT_ACCOUNT_ID=1
AUTHENTICATION_INSTANCE_CHATWOOT_TOKEN=123456
AUTHENTICATION_INSTANCE_CHATWOOT_URL=''

View File

@@ -0,0 +1,91 @@
version: '3.3'
services:
mongodb:
container_name: mongodb
image: mongo
restart: on-failure
ports:
- 27017:27017
environment:
- MONGO_INITDB_ROOT_USERNAME=root
- MONGO_INITDB_ROOT_PASSWORD=root
- PUID=1000
- PGID=1000
volumes:
- evolution_mongodb_data:/data/db
- evolution_mongodb_configdb:/data/configdb
expose:
- 27017
mongo-express:
container_name: mongodb-express
image: mongo-express
restart: on-failure
ports:
- 8081:8081
depends_on:
- mongodb
environment:
ME_CONFIG_BASICAUTH_USERNAME: root
ME_CONFIG_BASICAUTH_PASSWORD: root
ME_CONFIG_MONGODB_SERVER: mongodb
ME_CONFIG_MONGODB_ADMINUSERNAME: root
ME_CONFIG_MONGODB_ADMINPASSWORD: root
links:
- mongodb
redis:
container_name: redis
image: redis:latest
restart: on-failure
ports:
- 6379:6379
command: >
redis-server
--port 6379
--appendonly yes
volumes:
- evolution_redis:/data
rebrow:
container_name: rebrow
image: marian/rebrow
restart: on-failure
depends_on:
- redis
ports:
- 5001:5001
links:
- redis
api:
container_name: evolution_api
image: davidsongomes/evolution-api
restart: always
depends_on:
- mongodb
- redis
ports:
- 8080:8080
volumes:
- evolution_instances:/evolution/instances
- evolution_store:/evolution/store
env_file:
- .env
command: ['node', './dist/src/main.js']
expose:
- 8080
volumes:
evolution_mongodb_data:
evolution_mongodb_configdb:
evolution_redis:
evolution_instances:
evolution_store:
networks:
evolution-net:
external: true

View File

@@ -35,7 +35,8 @@ volumes:
evolution_mongodb_data:
evolution_mongodb_configdb:
networks:
evolution-net:
external: true
name: evolution-net
driver: bridge

View File

@@ -5,17 +5,17 @@ services:
image: redis:latest
container_name: redis
command: >
redis-server
--port 6379
--appendonly yes
redis-server --port 6379 --appendonly yes
volumes:
- evolution_redis:/data
ports:
- 6379:6379
volumes:
evolution_redis:
networks:
evolution-net:
external: true
name: evolution-net
driver: bridge

View File

@@ -1,18 +1,29 @@
FROM node:16.18-alpine
FROM node:20.7.0-alpine AS builder
LABEL version="1.1.3" description="Api to control whatsapp features through http requests."
LABEL version="1.6.1" description="Api to control whatsapp features through http requests."
LABEL maintainer="Davidson Gomes" git="https://github.com/DavidsonGomes"
LABEL contact="contato@agenciadgcode.com"
RUN apk update && apk upgrade && \
apk add --no-cache git
apk add --no-cache git tzdata ffmpeg wget curl
WORKDIR /evolution
COPY ./package.json .
RUN npm install
COPY . .
RUN npm run build
FROM node:20.7.0-alpine AS final
ENV TZ=America/Sao_Paulo
ENV DOCKER_ENV=true
ENV SERVER_TYPE=http
ENV SERVER_PORT=8080
ENV SERVER_URL=http://localhost:8080
ENV CORS_ORIGIN=*
@@ -50,12 +61,25 @@ ENV REDIS_ENABLED=false
ENV REDIS_URI=redis://redis:6379
ENV REDIS_PREFIX_KEY=evolution
ENV WEBHOOK_GLOBAL_URL=<url>
ENV RABBITMQ_ENABLED=false
ENV RABBITMQ_URI=amqp://guest:guest@rabbitmq:5672
ENV WEBSOCKET_ENABLED=false
ENV SQS_ENABLED=false
ENV SQS_ACCESS_KEY_ID=
ENV SQS_SECRET_ACCESS_KEY=
ENV SQS_ACCOUNT_ID=
ENV SQS_REGION=
ENV WEBHOOK_GLOBAL_URL=
ENV WEBHOOK_GLOBAL_ENABLED=false
ENV WEBHOOK_GLOBAL_WEBHOOK_BY_EVENTS=false
ENV WEBHOOK_EVENTS_APPLICATION_STARTUP=false
ENV WEBHOOK_EVENTS_INSTANCE_CREATE=false
ENV WEBHOOK_EVENTS_INSTANCE_DELETE=false
ENV WEBHOOK_EVENTS_QRCODE_UPDATED=true
ENV WEBHOOK_EVENTS_MESSAGES_SET=true
ENV WEBHOOK_EVENTS_MESSAGES_UPSERT=true
@@ -78,10 +102,21 @@ ENV WEBHOOK_EVENTS_CALL=true
ENV WEBHOOK_EVENTS_NEW_JWT_TOKEN=false
ENV WEBHOOK_EVENTS_TYPEBOT_START=false
ENV WEBHOOK_EVENTS_TYPEBOT_CHANGE_STATUS=false
ENV WEBHOOK_EVENTS_CHAMA_AI_ACTION=false
ENV WEBHOOK_EVENTS_ERRORS=false
ENV WEBHOOK_EVENTS_ERRORS_WEBHOOK=
ENV CONFIG_SESSION_PHONE_CLIENT=EvolutionAPI
ENV CONFIG_SESSION_PHONE_NAME=chrome
ENV CONFIG_SESSION_PHONE_NAME=Chrome
ENV QRCODE_LIMIT=30
ENV QRCODE_COLOR=#198754
ENV TYPEBOT_API_VERSION=latest
ENV AUTHENTICATION_TYPE=apikey
@@ -99,10 +134,8 @@ ENV AUTHENTICATION_INSTANCE_CHATWOOT_ACCOUNT_ID=1
ENV AUTHENTICATION_INSTANCE_CHATWOOT_TOKEN=123456
ENV AUTHENTICATION_INSTANCE_CHATWOOT_URL=<url>
RUN npm install
WORKDIR /evolution
COPY . .
RUN npm run build
COPY --from=builder /evolution .
CMD [ "node", "./dist/src/main.js" ]

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,241 @@
{
"name": "[Evolution] Configurar Admin",
"nodes": [
{
"parameters": {
"values": {
"string": [
{
"name": "api_access_token",
"value": "CHATWOOT_ADMIN_USER_TOKEN"
},
{
"name": "chatwoot_url",
"value": "https://CHATWOOT_URL"
},
{
"name": "n8n_url",
"value": "https://N8N_URL"
},
{
"name": "organization",
"value": "ORGANIZATION_NAME"
},
{
"name": "logo",
"value": "ORGANIZATION_LOGO"
}
]
},
"options": {}
},
"id": "7a89a538-2cae-4032-8896-09627c07bc68",
"name": "Info Base",
"type": "n8n-nodes-base.set",
"typeVersion": 2,
"position": [
620,
480
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $('Info Base').item.json[\"chatwoot_url\"] }}/api/v1/accounts/1/contacts/",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "api_access_token",
"value": "={{ $('Info Base').item.json[\"api_access_token\"] }}"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"inbox_id\": {{ $('Cria Inbox Start').item.json[\"id\"] }},\n \"name\": \"Bot {{ $('Info Base').item.json[\"organization\"] }}\",\n \"phone_number\": \"+123456\",\n \"avatar_url\": \"{{ $('Info Base').item.json[\"logo\"] }}\"\n}",
"options": {}
},
"id": "12a39df3-6b95-4f83-a0bc-50b25adaca7f",
"name": "Cria Contato Bot",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
1020,
480
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $('Info Base').item.json[\"chatwoot_url\"] }}/api/v1/accounts/1/inboxes/",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "api_access_token",
"value": "={{ $('Info Base').item.json[\"api_access_token\"] }}"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"name\": \"Start {{ $('Info Base').item.json[\"organization\"] }}\",\n \"channel\": {\n \"type\": \"api\",\n \"website_url\": \"\"\n }\n}",
"options": {}
},
"id": "bed7c54d-e232-4fe4-9584-0515e9679868",
"name": "Cria Inbox Start",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
820,
480
]
},
{
"parameters": {},
"id": "36ada769-a757-4193-989b-0cc4ea504b80",
"name": "When clicking \"Execute Workflow\"",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [
420,
480
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $('Info Base').item.json[\"chatwoot_url\"] }}/api/v1/accounts/1/automation_rules/",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "api_access_token",
"value": "={{ $('Info Base').item.json[\"api_access_token\"] }}"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"name\": \"Create Company Chatwoot\",\n \"description\": \"Create Company Chatwoot\",\n \"event_name\": \"message_created\",\n \"active\": true,\n \"actions\": \n [\n {\n \"action_name\": \"send_webhook_event\",\n \"action_params\": [\"{{ $('Info Base').item.json[\"n8n_url\"] }}/webhook/criadorchatwoot\"]\n }\n ],\n \"conditions\": \n [\n {\n \"attribute_key\": \"content\",\n \"filter_operator\": \"contains\",\n \"query_operator\": \"and\",\n \"values\": [\"Tema Criador de Empresa:\"]\n },\n {\n \"attribute_key\": \"phone_number\",\n \"filter_operator\": \"equal_to\",\n \"values\": [\"+123456\"]\n }\n ]\n}",
"options": {}
},
"id": "f5bbb285-71a8-4c58-a4d7-e56002d697f0",
"name": "Cria Automação Empresas",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
1220,
480
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $('Info Base').item.json[\"chatwoot_url\"] }}/api/v1/accounts/1/automation_rules/",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "api_access_token",
"value": "={{ $('Info Base').item.json[\"api_access_token\"] }}"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"name\": \"Create Inbox {{ $('Info Base').item.json[\"organization\"] }}\",\n \"description\": \"Create Inbox {{ $('Info Base').item.json[\"organization\"] }}\",\n \"event_name\": \"message_created\",\n \"active\": true,\n \"actions\": \n [\n {\n \"action_name\": \"send_webhook_event\",\n \"action_params\": [\"{{ $('Info Base').item.json[\"n8n_url\"] }}/webhook/inbox_whatsapp?utoken={{ $('Info Base').item.json[\"api_access_token\"] }}&organization={{ $('Info Base').item.json[\"organization\"] }}\"]\n }\n ],\n \"conditions\": \n [\n {\n \"attribute_key\": \"content\",\n \"filter_operator\": \"contains\",\n \"query_operator\": \"and\",\n \"values\": [\"start:\"]\n },\n \n {\n \"attribute_key\": \"phone_number\",\n \"filter_operator\": \"equal_to\",\n \"query_operator\": \"or\",\n \"values\": [\"+123456\"]\n },\n\n\n {\n \"attribute_key\": \"content\",\n \"filter_operator\": \"contains\",\n \"query_operator\": \"and\",\n \"values\": [\"new_instance:\"]\n },\n {\n \"attribute_key\": \"phone_number\",\n \"filter_operator\": \"equal_to\",\n \"values\": [\"+123456\"]\n }\n ]\n}",
"options": {}
},
"id": "a36bebdc-a318-40a2-8532-c7f476f8adb7",
"name": "Cria Automação Inboxes",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
1420,
480
]
},
{
"parameters": {
"content": "## Workflow Para Configurar admin\n**Aqui você prepara o Chatwoot Principal com um usuário (Superadmin) que poderá criar empresas e caixas de entrada**\n**Instruções**\n**No node Info Base, configure as variáveis de seu Chatwoot e N8N**\n**Obs: A variável api_access_token é o token do usuário que irá poder criar as empresas**",
"width": 894.6435495898575
},
"id": "db66e867-e9f4-452d-b521-725eeac652c8",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
420,
280
]
}
],
"pinData": {},
"connections": {
"Info Base": {
"main": [
[
{
"node": "Cria Inbox Start",
"type": "main",
"index": 0
}
]
]
},
"Cria Contato Bot": {
"main": [
[
{
"node": "Cria Automação Empresas",
"type": "main",
"index": 0
}
]
]
},
"Cria Inbox Start": {
"main": [
[
{
"node": "Cria Contato Bot",
"type": "main",
"index": 0
}
]
]
},
"When clicking \"Execute Workflow\"": {
"main": [
[
{
"node": "Info Base",
"type": "main",
"index": 0
}
]
]
},
"Cria Automação Empresas": {
"main": [
[
{
"node": "Cria Automação Inboxes",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {},
"versionId": "78f155dc-7809-4bfc-9282-63f49b07fc4d",
"id": "BSATyGpGWLR4ZwNm",
"meta": {
"instanceId": "4ff16e963c7f5197d7e99e6239192860914312fea0ce2a9a7fd14d74a0a0e906"
},
"tags": []
}

View File

@@ -0,0 +1,456 @@
{
"name": "[Evolution] Criador de Empresas",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "criadorchatwoot",
"options": {}
},
"id": "5a47c10a-e43c-4fa5-baad-4b6cc511bfcd",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [
1420,
860
],
"webhookId": "6fe428e3-1752-453c-9358-abf18b793387"
},
{
"parameters": {
"method": "POST",
"url": "={{ $('Info Base').item.json[\"chatwoot_url\"] }}/platform/api/v1/accounts",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "api_access_token",
"value": "={{ $('Info Base').item.json[\"api_access_token\"] }}"
}
]
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "name",
"value": "={{ $json.name_company }}"
},
{
"name": "locale",
"value": "pt_BR"
}
]
},
"options": {}
},
"id": "8295c119-3a96-424e-9386-43d75f6816f5",
"name": "Cria Conta",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
2020,
860
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $('Info Base').item.json[\"chatwoot_url\"] }}/platform/api/v1/users",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "api_access_token",
"value": "={{ $('Info Base').item.json[\"api_access_token\"] }}"
}
]
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "name",
"value": "={{ $('Info Base').item.json.name_admin }}"
},
{
"name": "email",
"value": "={{ $('Info Base').item.json[\"email\"] }}"
},
{
"name": "password",
"value": "={{ $('Info Base').item.json[\"password\"] }}"
}
]
},
"options": {}
},
"id": "4fe5007a-3a6b-490a-a446-e45cc168189f",
"name": "Cria Usuario",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
2220,
860
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $('Info Base').item.json[\"chatwoot_url\"] }}/platform/api/v1/accounts/{{ $node[\"Cria Conta\"].json[\"id\"] }}/account_users",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "api_access_token",
"value": "={{ $('Info Base').item.json[\"api_access_token\"] }}"
}
]
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "user_id",
"value": "={{ $node[\"Cria Usuario\"].json[\"id\"] }}"
},
{
"name": "role",
"value": "administrator"
}
]
},
"options": {}
},
"id": "848c55e2-5678-4291-9602-c94d994da95b",
"name": "Add Usuario a Conta",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
2420,
860
]
},
{
"parameters": {
"fromEmail": "={{ $('Info Base').item.json[\"from_email\"] }}",
"toEmail": "={{ $('LimpaDados').item.json.email }}",
"subject": "=Bem vindo à {{ $('Info Base').item.json[\"organization\"] }}",
"text": "=Olá seja bem vindo:\n\nAbaixo segue seus dados de acesso:\n\nURL: {{ $('Info Base').item.json[\"chatwoot_url\"] }}\n\nuser: {{ $('LimpaDados').item.json[\"email\"] }}\n\nSenha: {{ $('LimpaDados').item.json[\"password\"] }}",
"options": {}
},
"id": "27f3b24f-1cf2-4d0d-a354-ecba066059f6",
"name": "Send Email",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 2,
"position": [
3220,
860
],
"credentials": {
"smtp": {
"id": "6BxluEUV8zrXKoVG",
"name": "[Dgcode] SMTP"
}
}
},
{
"parameters": {
"values": {
"string": [
{
"name": "api_access_token",
"value": "CHATWOOT_PLATFORM_TOKEN"
},
{
"name": "chatwoot_url",
"value": "https://CHATWOOT_URL"
},
{
"name": "n8n_url",
"value": "https://N8N_URL"
},
{
"name": "organization",
"value": "ORGANIZATION_NAME"
},
{
"name": "logo",
"value": "ORGANIZATION_LOGO"
},
{
"name": "from_email",
"value": "FROM_EMAIL"
},
{
"name": "name",
"value": "={{ $json.name_company }}"
},
{
"name": "email",
"value": "={{ $json.email }}"
},
{
"name": "password",
"value": "={{ $json.password }}"
},
{
"name": "name_company",
"value": "={{ $json.name_company }}"
}
]
},
"options": {}
},
"id": "38b4069d-e51e-4db7-933f-941b1be6d124",
"name": "Info Base",
"type": "n8n-nodes-base.set",
"typeVersion": 2,
"position": [
1820,
860
]
},
{
"parameters": {
"keepOnlySet": true,
"values": {
"string": [
{
"name": "name_admin",
"value": "={{$node[\"Webhook\"].json[\"body\"][\"messages\"][0][\"content\"].match(/Nome Usuario Administrador: ([^\\n]+)/)[1];}}"
},
{
"name": "name_company",
"value": "={{$node[\"Webhook\"].json[\"body\"][\"messages\"][0][\"content\"].match(/Nome da Empresa: ([^\\n]+)/)[1];}}"
},
{
"name": "email",
"value": "={{$node[\"Webhook\"].json[\"body\"][\"messages\"][0][\"content\"].match(/Email: ([^\\s]+)/)[1];}}"
},
{
"name": "password",
"value": "={{$node[\"Webhook\"].json[\"body\"][\"messages\"][0][\"content\"].match(/Senha: ([^\\s]+)/)[1];}}"
}
]
},
"options": {}
},
"id": "28e29e73-aadc-49ca-bd6d-b57ee0160a21",
"name": "LimpaDados",
"type": "n8n-nodes-base.set",
"typeVersion": 2,
"position": [
1620,
860
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $('Info Base').item.json[\"chatwoot_url\"] }}/api/v1/accounts/{{ $('Add Usuario a Conta').item.json.account_id }}/contacts/",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "api_access_token",
"value": "={{ $('Cria Usuario').item.json.access_token }}"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"inbox_id\": {{ $('Cria Inbox Start').item.json[\"id\"] }},\n \"name\": \"Bot {{ $('Info Base').item.json[\"organization\"] }}\",\n \"phone_number\": \"+123456\",\n \"avatar_url\": \"{{ $('Info Base').item.json[\"logo\"] }}\"\n}",
"options": {}
},
"id": "bb671443-bdb4-4f56-99af-f0baef246a3e",
"name": "Cria Contato Bot",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
2820,
860
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $('Info Base').item.json[\"chatwoot_url\"] }}/api/v1/accounts/{{ $('Add Usuario a Conta').item.json.account_id }}/automation_rules/",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "api_access_token",
"value": "={{ $('Cria Usuario').item.json.access_token }}"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"name\": \"Create Inbox {{ $('Info Base').item.json[\"organization\"] }}\",\n \"description\": \"Create Inbox {{ $('Info Base').item.json[\"organization\"] }}\",\n \"event_name\": \"message_created\",\n \"active\": true,\n \"actions\": \n [\n {\n \"action_name\": \"send_webhook_event\",\n \"action_params\": [\"{{ $('Info Base').item.json[\"n8n_url\"] }}/webhook/inbox_whatsapp?utoken={{ $('Cria Usuario').item.json.access_token }}&organization={{ $('Info Base').item.json[\"organization\"] }}\"]\n }\n ],\n \"conditions\": \n [\n {\n \"attribute_key\": \"content\",\n \"filter_operator\": \"contains\",\n \"query_operator\": \"and\",\n \"values\": [\"start:\"]\n },\n {\n \"attribute_key\": \"phone_number\",\n \"filter_operator\": \"equal_to\",\n \"query_operator\": \"or\",\n \"values\": [\"+123456\"]\n },\n {\n \"attribute_key\": \"content\",\n \"filter_operator\": \"contains\",\n \"query_operator\": \"and\",\n \"values\": [\"new_instance:\"]\n },\n {\n \"attribute_key\": \"phone_number\",\n \"filter_operator\": \"equal_to\",\n \"values\": [\"+123456\"]\n }\n ]\n}",
"options": {}
},
"id": "e016a2af-b212-4e00-a3ff-8cd03530aa06",
"name": "Cria Automação",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
3020,
860
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $('Info Base').item.json[\"chatwoot_url\"] }}/api/v1/accounts/{{ $json.account_id }}/inboxes/",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "api_access_token",
"value": "={{ $('Cria Usuario').item.json.access_token }}"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"name\": \"Start {{ $('Info Base').item.json[\"organization\"] }}\",\n \"channel\": {\n \"type\": \"api\",\n \"website_url\": \"\"\n }\n}",
"options": {}
},
"id": "d3c42148-8920-4c98-a874-eb7113f2dd22",
"name": "Cria Inbox Start",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
2620,
860
]
},
{
"parameters": {
"content": "## Workflow Criador de Empresas\n**Cria Contas (Empresas) e Usuários através de tema**\n**Instruções**\n**No node Info Base, configure as variáveis de seu Chatwoot e N8N**\n**Obs: A variável api_access_token é o token PlatformApp encontrado no acesso ao Super Admin**\n**Tema para criar novas empresa:**\n\nTema Criador de Empresa:\n\nNome Usuario Administrador: Joao Linhares\nNome da Empresa: Oficina Linhates\nEmail: machineteste24@gmail.com\nSenha: Mfcd62!!",
"height": 304.02684563758396,
"width": 1129.7777777777778
},
"id": "d07516c0-4c8e-43ab-ba86-c8d063b09be5",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
1420,
520
]
}
],
"pinData": {},
"connections": {
"Webhook": {
"main": [
[
{
"node": "LimpaDados",
"type": "main",
"index": 0
}
]
]
},
"Cria Conta": {
"main": [
[
{
"node": "Cria Usuario",
"type": "main",
"index": 0
}
]
]
},
"Cria Usuario": {
"main": [
[
{
"node": "Add Usuario a Conta",
"type": "main",
"index": 0
}
]
]
},
"Add Usuario a Conta": {
"main": [
[
{
"node": "Cria Inbox Start",
"type": "main",
"index": 0
}
]
]
},
"Info Base": {
"main": [
[
{
"node": "Cria Conta",
"type": "main",
"index": 0
}
]
]
},
"LimpaDados": {
"main": [
[
{
"node": "Info Base",
"type": "main",
"index": 0
}
]
]
},
"Cria Contato Bot": {
"main": [
[
{
"node": "Cria Automação",
"type": "main",
"index": 0
}
]
]
},
"Cria Automação": {
"main": [
[
{
"node": "Send Email",
"type": "main",
"index": 0
}
]
]
},
"Cria Inbox Start": {
"main": [
[
{
"node": "Cria Contato Bot",
"type": "main",
"index": 0
}
]
]
}
},
"active": true,
"settings": {},
"versionId": "3ffd6d3f-6966-4de4-af8f-1fda464bc1b8",
"id": "79R6qQDtfyCwgYjJ",
"meta": {
"instanceId": "4ff16e963c7f5197d7e99e6239192860914312fea0ce2a9a7fd14d74a0a0e906"
},
"tags": []
}

View File

@@ -0,0 +1,510 @@
{
"name": "[Evolution] Criador de Inbox",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "inbox_whatsapp",
"options": {}
},
"id": "8205b929-73e9-456a-9b0d-e1474991663a",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [
320,
300
],
"webhookId": "cf37002d-3869-4bb1-af3a-739fdd3c1756"
},
{
"parameters": {
"method": "POST",
"url": "={{ $json.evolution_url }}/instance/create",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "apikey",
"value": "={{ $json.global_api_key }}"
}
]
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "instanceName",
"value": "={{ $json.instance_name }}"
},
{
"name": "qrcode",
"value": "={{ $json.qrcode }}"
},
{
"name": "chatwoot_account_id",
"value": "={{ $json.chatwoot_account_id }}"
},
{
"name": "chatwoot_token",
"value": "={{ $json.chatwoot_token }}"
},
{
"name": "chatwoot_url",
"value": "={{ $json.chatwoot_url }}"
},
{
"name": "chatwoot_sign_msg",
"value": "={{ $json.chatwoot_sign_msg }}"
},
{
"name": "chatwoot_reopen_conversation",
"value": "={{ $json.chatwoot_reopen_conversation }}"
},
{
"name": "chatwoot_conversation_pending",
"value": "={{ $json.chatwoot_conversation_pending }}"
},
{
"name": "reject_call",
"value": "={{ $json.reject_call }}"
},
{
"name": "msg_call",
"value": "={{ $json.msg_call }}"
},
{
"name": "groups_ignore",
"value": "={{ $json.groups_ignore }}"
},
{
"name": "always_online",
"value": "={{ $json.always_online }}"
},
{
"name": "read_messages",
"value": "={{ $json.read_messages }}"
},
{
"name": "read_status",
"value": "={{ $json.read_status }}"
}
]
},
"options": {}
},
"id": "275aa370-2fdb-42f4-844a-2fb3051301bd",
"name": "Cria Instancia",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"position": [
760,
300
]
},
{
"parameters": {
"url": "={{ $('Info Base').item.json[\"chatwoot_url\"] }}/api/v1/accounts/{{ $('Info Base').item.json[\"chatwoot_account_id\"] }}/inboxes/",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "api_access_token",
"value": "={{ $('Info Base').item.json.chatwoot_token }}"
}
]
},
"options": {}
},
"id": "e4650812-ba0a-4f72-8bd8-a235eca4b2de",
"name": "Lista Inboxes",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
980,
300
]
},
{
"parameters": {
"content": "## Workflow Para Criar Inbox\n**Aqui você configura a comunicação entre o chatwoot e a Evolution API para criar novas instâncias a partir do chatwoot**\n**Instruções**\n**No node Info Base, configure as variáveis de seu Chatwoot e Evolution API**",
"width": 1129.7777777777778
},
"id": "aa763d9e-d973-44fc-8399-277bb24718a5",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
320,
80
]
},
{
"parameters": {
"keepOnlySet": true,
"values": {
"string": [
{
"name": "chatwoot_url",
"value": "CHATWOOT_URL"
},
{
"name": "evolution_url",
"value": "EVOLUTION_URL"
},
{
"name": "global_api_key",
"value": "EVOLUTION_GLOBAL_API_KEY"
},
{
"name": "organization",
"value": "={{ $json.query.organization }}"
},
{
"name": "instance_name",
"value": "={{ $json.body.messages[0].content.split(':')[1] }}-cwId-{{ $json.body.messages[0].account_id }}"
},
{
"name": "chatwoot_token",
"value": "={{ $json.query.utoken }}"
},
{
"name": "msg_call",
"value": "Não aceitamos chamadas, por favor deixe uma mensagem!"
}
],
"boolean": [
{
"name": "qrcode",
"value": true
},
{
"name": "chatwoot_sign_msg",
"value": true
},
{
"name": "chatwoot_reopen_conversation",
"value": true
},
{
"name": "chatwoot_conversation_pending"
},
{
"name": "reject_call",
"value": true
},
{
"name": "groups_ignore"
},
{
"name": "always_online",
"value": true
},
{
"name": "read_messages",
"value": true
},
{
"name": "read_status"
}
],
"number": [
{
"name": "chatwoot_account_id",
"value": "={{ $json.body.messages[0].account_id }}"
}
]
},
"options": {}
},
"id": "297df325-ecc4-4a34-817c-092d16d5753b",
"name": "Info Base",
"type": "n8n-nodes-base.set",
"typeVersion": 2,
"position": [
540,
300
]
},
{
"parameters": {
"conditions": {
"string": [
{
"value1": "={{ $json.name }}",
"value2": "=Start {{ $('Info Base').item.json[\"organization\"] }}"
}
]
}
},
"id": "a8d955e6-ac51-4316-aeec-09d4d65e943a",
"name": "é Start Inbox?",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
1660,
200
]
},
{
"parameters": {
"batchSize": 1,
"options": {}
},
"id": "0d2d2194-aa4a-4241-9022-217d88bb581f",
"name": "Split In Batches",
"type": "n8n-nodes-base.splitInBatches",
"typeVersion": 2,
"position": [
1420,
300
]
},
{
"parameters": {
"conditions": {
"string": [
{
"value1": "={{ $json.name }}",
"value2": "={{ $('Webhook').item.json[\"body\"][\"messages\"][0][\"content\"].split(':')[1] }}"
}
]
}
},
"id": "0bfbc2cb-eff5-423c-bd3a-b266aaf6a943",
"name": "é_pre-existente?",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
1900,
340
]
},
{
"parameters": {
"method": "PATCH",
"url": "={{ $('Info Base').item.json[\"chatwoot_url\"] }}/api/v1/accounts/{{ $('Info Base').item.json[\"chatwoot_account_id\"] }}/inboxes/{{ $json.id }}",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "api_access_token",
"value": "={{ $('Info Base').item.json.chatwoot_token }}"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n\"channel\": {\n\"webhook_url\": \"{{ $('Info Base').item.json[\"evolution_url\"] }}/chatwoot/webhook/{{ encodeURIComponent($('Info Base').item.json[\"instance_name\"]) }}\"\n}\n}",
"options": {}
},
"id": "fb589456-5566-4a45-96a7-75986d0aa1d5",
"name": "Update_webhook_url",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
2120,
340
]
},
{
"parameters": {
"method": "DELETE",
"url": "={{ $('Info Base').item.json[\"chatwoot_url\"] }}/api/v1/accounts/{{ $('Info Base').item.json[\"chatwoot_account_id\"] }}/inboxes/{{ $json.id }}",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "api_access_token",
"value": "={{ $('Info Base').item.json.chatwoot_token }}"
}
]
},
"options": {}
},
"id": "e6094941-410f-496c-9c9c-7b95fd9349af",
"name": "Deleta Inbox Start",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
1900,
100
]
},
{
"parameters": {},
"id": "8cf9a78f-9e8a-4288-9d7b-801790af68d5",
"name": "No Operation, do nothing",
"type": "n8n-nodes-base.noOp",
"typeVersion": 1,
"position": [
1660,
400
]
},
{
"parameters": {
"fieldToSplitOut": "payload",
"options": {}
},
"id": "9468896a-5f86-4598-9d20-e8f495cae859",
"name": "Ajusta lista",
"type": "n8n-nodes-base.itemLists",
"typeVersion": 2.2,
"position": [
1200,
300
]
}
],
"pinData": {},
"connections": {
"Webhook": {
"main": [
[
{
"node": "Info Base",
"type": "main",
"index": 0
}
]
]
},
"Lista Inboxes": {
"main": [
[
{
"node": "Ajusta lista",
"type": "main",
"index": 0
}
]
]
},
"Cria Instancia": {
"main": [
[
{
"node": "Lista Inboxes",
"type": "main",
"index": 0
}
]
]
},
"Info Base": {
"main": [
[
{
"node": "Cria Instancia",
"type": "main",
"index": 0
}
]
]
},
"é Start Inbox?": {
"main": [
[
{
"node": "Deleta Inbox Start",
"type": "main",
"index": 0
}
],
[
{
"node": "é_pre-existente?",
"type": "main",
"index": 0
}
]
]
},
"Split In Batches": {
"main": [
[
{
"node": "é Start Inbox?",
"type": "main",
"index": 0
}
],
[
{
"node": "No Operation, do nothing",
"type": "main",
"index": 0
}
]
]
},
"é_pre-existente?": {
"main": [
[
{
"node": "Update_webhook_url",
"type": "main",
"index": 0
}
],
[
{
"node": "Split In Batches",
"type": "main",
"index": 0
}
]
]
},
"Update_webhook_url": {
"main": [
[
{
"node": "Split In Batches",
"type": "main",
"index": 0
}
]
]
},
"Deleta Inbox Start": {
"main": [
[
{
"node": "Split In Batches",
"type": "main",
"index": 0
}
]
]
},
"Ajusta lista": {
"main": [
[
{
"node": "Split In Batches",
"type": "main",
"index": 0
}
]
]
}
},
"active": true,
"settings": {},
"versionId": "ab910349-b559-4738-9ac6-de6b06d6bbce",
"id": "ByW2ccjR4XPrOyio",
"meta": {
"instanceId": "4ff16e963c7f5197d7e99e6239192860914312fea0ce2a9a7fd14d74a0a0e906"
},
"tags": []
}

File diff suppressed because one or more lines are too long

View File

@@ -7,7 +7,8 @@
[![Postman Collection](https://img.shields.io/badge/Postman-Collection-orange)](https://evolution-api.com/postman)
[![Documentation](https://img.shields.io/badge/Documentation-Official-green)](https://doc.evolution-api.com)
[![License](https://img.shields.io/badge/license-GPL--3.0-orange)](./LICENSE)
[![Support](https://img.shields.io/badge/Buy%20me-coffe-orange)](https://app.picpay.com/user/davidsongomes1998)
[![Support](https://img.shields.io/badge/Donation-picpay-green)](https://app.picpay.com/user/davidsongomes1998)
[![Support](https://img.shields.io/badge/Buy%20me-coffe-orange)](https://bmc.link/evolutionapi)
</div>
@@ -34,8 +35,17 @@ This code was produced based on the baileys library and it is still under develo
<div align="center">
<a href="https://app.picpay.com/user/davidsongomes1998" target="_blank" rel="noopener noreferrer">
<img src="./public/images/picpay-image.png" style="width: 50% !important;">
<img src="./public/images/picpay-qr.jpeg" style="width: 50% !important;">
</a>
</div>
#### Buy me coffe - PIX
<div align="center">
<a href="https://bmc.link/evolutionapi" target="_blank" rel="noopener noreferrer">
<img src="./public/images/qrcode-pix.png" style="width: 50% !important;">
</a>
<p><b>CHAVE PIX (Telefone):</b> (74)99987-9409</p>
</div>
</br>

View File

@@ -4,6 +4,7 @@ services:
api:
container_name: evolution_api
image: evolution/api:local
build: .
restart: always
ports:
- 8080:8080
@@ -24,5 +25,5 @@ volumes:
networks:
evolution-net:
external: true
name: evolution-net
driver: bridge

View File

@@ -4,6 +4,7 @@ services:
api:
container_name: evolution_api
image: evolution/api:local
build: .
restart: always
ports:
- 8080:8080
@@ -75,5 +76,5 @@ volumes:
networks:
evolution-net:
external: true
name: evolution-net
driver: bridge

View File

@@ -3,7 +3,7 @@ version: '3.3'
services:
api:
container_name: evolution_api
image: davidsongomes/evolution-api:latest
image: atendai/evolution-api:latest
restart: always
ports:
- 8080:8080
@@ -24,5 +24,5 @@ volumes:
networks:
evolution-net:
external: true
name: evolution-net
driver: bridge

View File

@@ -1,13 +0,0 @@
#!/bin/bash
NET='evolution-net'
IMAGE='evolution/api:local'
if !(docker network ls | grep ${NET} > /dev/null)
then
docker network create -d bridge ${NET}
fi
docker build -t ${IMAGE} .
docker compose up -d

View File

@@ -1,6 +1,6 @@
{
"name": "evolution-api",
"version": "1.4.7",
"version": "1.6.1",
"description": "Rest api for communication with WhatsApp",
"main": "./dist/src/main.js",
"scripts": {
@@ -43,10 +43,12 @@
"dependencies": {
"@adiwajshing/keyed-db": "^0.2.4",
"@ffmpeg-installer/ffmpeg": "^1.1.0",
"@figuro/chatwoot-sdk": "^1.1.14",
"@figuro/chatwoot-sdk": "^1.1.16",
"@hapi/boom": "^10.0.1",
"@sentry/node": "^7.59.2",
"@whiskeysockets/baileys": "github:EvolutionAPI/Baileys",
"@whiskeysockets/baileys": "github:PurpShell/Baileys#combined",
"amqplib": "^0.10.3",
"aws-sdk": "^2.1499.0",
"axios": "^1.3.5",
"class-validator": "^0.13.2",
"compression": "^1.7.4",
@@ -54,6 +56,7 @@
"cross-env": "^7.0.3",
"dayjs": "^1.11.7",
"eventemitter2": "^6.4.9",
"evolution-manager": "^0.4.11",
"exiftool-vendored": "^22.0.0",
"express": "^4.18.2",
"express-async-errors": "^3.1.1",
@@ -63,17 +66,23 @@
"js-yaml": "^4.1.0",
"jsonschema": "^1.4.1",
"jsonwebtoken": "^8.5.1",
"libphonenumber-js": "^1.10.39",
"link-preview-js": "^3.0.4",
"mongoose": "^6.10.5",
"node-cache": "^5.1.2",
"node-mime-types": "^1.1.0",
"node-windows": "^1.0.0-beta.8",
"pino": "^8.11.0",
"proxy-agent": "^6.2.1",
"proxy-agent": "^6.3.0",
"qrcode": "^1.5.1",
"qrcode-terminal": "^0.12.0",
"redis": "^4.6.5",
"sharp": "^0.30.7",
"uuid": "^9.0.0"
"socket.io": "^4.7.1",
"socks-proxy-agent": "^8.0.1",
"swagger-ui-express": "^5.0.0",
"uuid": "^9.0.0",
"yamljs": "^0.3.0"
},
"devDependencies": {
"@types/compression": "^1.7.2",
@@ -83,6 +92,7 @@
"@types/jsonwebtoken": "^8.5.9",
"@types/mime-types": "^2.1.1",
"@types/node": "^18.15.11",
"@types/node-windows": "^0.1.2",
"@types/qrcode": "^1.5.0",
"@types/qrcode-terminal": "^0.12.0",
"@types/uuid": "^8.3.4",

BIN
public/images/bmc_qr.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@@ -3,7 +3,13 @@ import { readFileSync } from 'fs';
import { load } from 'js-yaml';
import { join } from 'path';
export type HttpServer = { TYPE: 'http' | 'https'; PORT: number; URL: string };
export type HttpServer = {
TYPE: 'http' | 'https';
PORT: number;
URL: string;
DISABLE_DOCS: boolean;
DISABLE_MANAGER: boolean;
};
export type HttpMethods = 'POST' | 'GET' | 'PUT' | 'DELETE';
export type Cors = {
@@ -61,8 +67,27 @@ export type Redis = {
PREFIX_KEY: string;
};
export type Rabbitmq = {
ENABLED: boolean;
URI: string;
};
export type Sqs = {
ENABLED: boolean;
ACCESS_KEY_ID: string;
SECRET_ACCESS_KEY: string;
ACCOUNT_ID: string;
REGION: string;
};
export type Websocket = {
ENABLED: boolean;
};
export type EventsWebhook = {
APPLICATION_STARTUP: boolean;
INSTANCE_CREATE: boolean;
INSTANCE_DELETE: boolean;
QRCODE_UPDATED: boolean;
MESSAGES_SET: boolean;
MESSAGES_UPSERT: boolean;
@@ -83,6 +108,11 @@ export type EventsWebhook = {
GROUP_PARTICIPANTS_UPDATE: boolean;
CALL: boolean;
NEW_JWT_TOKEN: boolean;
TYPEBOT_START: boolean;
TYPEBOT_CHANGE_STATUS: boolean;
CHAMA_AI_ACTION: boolean;
ERRORS: boolean;
ERRORS_WEBHOOK: string;
};
export type ApiKey = { KEY: string };
@@ -105,7 +135,8 @@ export type GlobalWebhook = {
export type SslConf = { PRIVKEY: string; FULLCHAIN: string };
export type Webhook = { GLOBAL?: GlobalWebhook; EVENTS: EventsWebhook };
export type ConfigSessionPhone = { CLIENT: string; NAME: string };
export type QrCode = { LIMIT: number };
export type QrCode = { LIMIT: number; COLOR: string };
export type Typebot = { API_VERSION: string; KEEP_OPEN: boolean };
export type Production = boolean;
export interface Env {
@@ -116,11 +147,15 @@ export interface Env {
CLEAN_STORE: CleanStoreConf;
DATABASE: Database;
REDIS: Redis;
RABBITMQ: Rabbitmq;
SQS: Sqs;
WEBSOCKET: Websocket;
LOG: Log;
DEL_INSTANCE: DelInstance;
WEBHOOK: Webhook;
CONFIG_SESSION_PHONE: ConfigSessionPhone;
QRCODE: QrCode;
TYPEBOT: Typebot;
AUTHENTICATION: Auth;
PRODUCTION?: Production;
}
@@ -142,8 +177,8 @@ export class ConfigService {
this.env = !(process.env?.DOCKER_ENV === 'true') ? this.envYaml() : this.envProcess();
this.env.PRODUCTION = process.env?.NODE_ENV === 'PROD';
if (process.env?.DOCKER_ENV === 'true') {
this.env.SERVER.TYPE = 'http';
this.env.SERVER.PORT = 8080;
this.env.SERVER.TYPE = process.env.SERVER_TYPE as 'http' | 'http';
this.env.SERVER.PORT = Number.parseInt(process.env.SERVER_PORT) || 8080;
}
}
@@ -154,18 +189,20 @@ export class ConfigService {
private envProcess(): Env {
return {
SERVER: {
TYPE: process.env.SERVER_TYPE as 'http' | 'https',
PORT: Number.parseInt(process.env.SERVER_PORT),
TYPE: (process.env.SERVER_TYPE as 'http' | 'https') || 'http',
PORT: Number.parseInt(process.env.SERVER_PORT) || 8080,
URL: process.env.SERVER_URL,
DISABLE_DOCS: process.env?.SERVER_DISABLE_DOCS === 'true',
DISABLE_MANAGER: process.env?.SERVER_DISABLE_MANAGER === 'true',
},
CORS: {
ORIGIN: process.env.CORS_ORIGIN.split(','),
METHODS: process.env.CORS_METHODS.split(',') as HttpMethods[],
ORIGIN: process.env.CORS_ORIGIN.split(',') || ['*'],
METHODS: (process.env.CORS_METHODS.split(',') as HttpMethods[]) || ['POST', 'GET', 'PUT', 'DELETE'],
CREDENTIALS: process.env?.CORS_CREDENTIALS === 'true',
},
SSL_CONF: {
PRIVKEY: process.env?.SSL_CONF_PRIVKEY,
FULLCHAIN: process.env?.SSL_CONF_FULLCHAIN,
PRIVKEY: process.env?.SSL_CONF_PRIVKEY || '',
FULLCHAIN: process.env?.SSL_CONF_FULLCHAIN || '',
},
STORE: {
MESSAGES: process.env?.STORE_MESSAGES === 'true',
@@ -184,8 +221,8 @@ export class ConfigService {
},
DATABASE: {
CONNECTION: {
URI: process.env.DATABASE_CONNECTION_URI,
DB_PREFIX_NAME: process.env.DATABASE_CONNECTION_DB_PREFIX_NAME,
URI: process.env.DATABASE_CONNECTION_URI || '',
DB_PREFIX_NAME: process.env.DATABASE_CONNECTION_DB_PREFIX_NAME || 'evolution',
},
ENABLED: process.env?.DATABASE_ENABLED === 'true',
SAVE_DATA: {
@@ -198,11 +235,34 @@ export class ConfigService {
},
REDIS: {
ENABLED: process.env?.REDIS_ENABLED === 'true',
URI: process.env.REDIS_URI,
PREFIX_KEY: process.env.REDIS_PREFIX_KEY,
URI: process.env.REDIS_URI || '',
PREFIX_KEY: process.env.REDIS_PREFIX_KEY || 'evolution',
},
RABBITMQ: {
ENABLED: process.env?.RABBITMQ_ENABLED === 'true',
URI: process.env.RABBITMQ_URI || '',
},
SQS: {
ENABLED: process.env?.SQS_ENABLED === 'true',
ACCESS_KEY_ID: process.env.SQS_ACCESS_KEY_ID || '',
SECRET_ACCESS_KEY: process.env.SQS_SECRET_ACCESS_KEY || '',
ACCOUNT_ID: process.env.SQS_ACCOUNT_ID || '',
REGION: process.env.SQS_REGION || '',
},
WEBSOCKET: {
ENABLED: process.env?.WEBSOCKET_ENABLED === 'true',
},
LOG: {
LEVEL: process.env?.LOG_LEVEL.split(',') as LogLevel[],
LEVEL: (process.env?.LOG_LEVEL.split(',') as LogLevel[]) || [
'ERROR',
'WARN',
'DEBUG',
'INFO',
'LOG',
'VERBOSE',
'DARK',
'WEBHOOKS',
],
COLOR: process.env?.LOG_COLOR === 'true',
BAILEYS: (process.env?.LOG_BAILEYS as LogBaileys) || 'error',
},
@@ -211,12 +271,14 @@ export class ConfigService {
: Number.parseInt(process.env.DEL_INSTANCE) || false,
WEBHOOK: {
GLOBAL: {
URL: process.env?.WEBHOOK_GLOBAL_URL,
URL: process.env?.WEBHOOK_GLOBAL_URL || '',
ENABLED: process.env?.WEBHOOK_GLOBAL_ENABLED === 'true',
WEBHOOK_BY_EVENTS: process.env?.WEBHOOK_GLOBAL_WEBHOOK_BY_EVENTS === 'true',
},
EVENTS: {
APPLICATION_STARTUP: process.env?.WEBHOOK_EVENTS_APPLICATION_STARTUP === 'true',
INSTANCE_CREATE: process.env?.WEBHOOK_EVENTS_INSTANCE_CREATE === 'true',
INSTANCE_DELETE: process.env?.WEBHOOK_EVENTS_INSTANCE_DELETE === 'true',
QRCODE_UPDATED: process.env?.WEBHOOK_EVENTS_QRCODE_UPDATED === 'true',
MESSAGES_SET: process.env?.WEBHOOK_EVENTS_MESSAGES_SET === 'true',
MESSAGES_UPSERT: process.env?.WEBHOOK_EVENTS_MESSAGES_UPSERT === 'true',
@@ -237,26 +299,36 @@ export class ConfigService {
GROUP_PARTICIPANTS_UPDATE: process.env?.WEBHOOK_EVENTS_GROUP_PARTICIPANTS_UPDATE === 'true',
CALL: process.env?.WEBHOOK_EVENTS_CALL === 'true',
NEW_JWT_TOKEN: process.env?.WEBHOOK_EVENTS_NEW_JWT_TOKEN === 'true',
TYPEBOT_START: process.env?.WEBHOOK_EVENTS_TYPEBOT_START === 'true',
TYPEBOT_CHANGE_STATUS: process.env?.WEBHOOK_EVENTS_TYPEBOT_CHANGE_STATUS === 'true',
CHAMA_AI_ACTION: process.env?.WEBHOOK_EVENTS_CHAMA_AI_ACTION === 'true',
ERRORS: process.env?.WEBHOOK_EVENTS_ERRORS === 'true',
ERRORS_WEBHOOK: process.env?.WEBHOOK_EVENTS_ERRORS_WEBHOOK || '',
},
},
CONFIG_SESSION_PHONE: {
CLIENT: process.env?.CONFIG_SESSION_PHONE_CLIENT || 'Evolution API',
NAME: process.env?.CONFIG_SESSION_PHONE_NAME || 'chrome',
NAME: process.env?.CONFIG_SESSION_PHONE_NAME || 'Chrome',
},
QRCODE: {
LIMIT: Number.parseInt(process.env.QRCODE_LIMIT) || 30,
COLOR: process.env.QRCODE_COLOR || '#198754',
},
TYPEBOT: {
API_VERSION: process.env?.TYPEBOT_API_VERSION || 'old',
KEEP_OPEN: process.env.TYPEBOT_KEEP_OPEN === 'true',
},
AUTHENTICATION: {
TYPE: process.env.AUTHENTICATION_TYPE as 'jwt',
TYPE: process.env.AUTHENTICATION_TYPE as 'apikey',
API_KEY: {
KEY: process.env.AUTHENTICATION_API_KEY,
KEY: process.env.AUTHENTICATION_API_KEY || 'BQYHJGJHJ',
},
EXPOSE_IN_FETCH_INSTANCES: process.env?.AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES === 'true',
JWT: {
EXPIRIN_IN: Number.isInteger(process.env?.AUTHENTICATION_JWT_EXPIRIN_IN)
? Number.parseInt(process.env.AUTHENTICATION_JWT_EXPIRIN_IN)
: 3600,
SECRET: process.env.AUTHENTICATION_JWT_SECRET,
SECRET: process.env.AUTHENTICATION_JWT_SECRET || 'L=0YWt]b2w[WF>#>:&E`',
},
},
};

View File

@@ -1,6 +1,8 @@
import dayjs from 'dayjs';
import fs from 'fs';
import { configService, Log } from './env.config';
const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
const formatDateLog = (timestamp: number) =>
dayjs(timestamp)
@@ -74,6 +76,8 @@ export class Logger {
/*Command.UNDERSCORE +*/ Command.BRIGHT + Level[type],
'[Evolution API]',
Command.BRIGHT + Color[type],
`v${packageJson.version}`,
Command.BRIGHT + Color[type],
process.pid.toString(),
Command.RESET,
Command.BRIGHT + Color[type],

View File

@@ -9,6 +9,9 @@ SERVER:
TYPE: http # https
PORT: 8080 # 443
URL: localhost
DISABLE_MANAGER: false
DISABLE_DOCS: false
CORS:
ORIGIN:
@@ -79,6 +82,20 @@ REDIS:
URI: "redis://localhost:6379"
PREFIX_KEY: "evolution"
RABBITMQ:
ENABLED: false
URI: "amqp://guest:guest@localhost:5672"
SQS:
ENABLED: true
ACCESS_KEY_ID: ""
SECRET_ACCESS_KEY: ""
ACCOUNT_ID: ""
REGION: "us-east-1"
WEBSOCKET:
ENABLED: false
# Global Webhook Settings
# Each instance's Webhook URL and events will be requested at the time it is created
WEBHOOK:
@@ -113,15 +130,28 @@ WEBHOOK:
CALL: true
# This event fires every time a new token is requested via the refresh route
NEW_JWT_TOKEN: false
# This events is used with Typebot
TYPEBOT_START: false
TYPEBOT_CHANGE_STATUS: false
# This event is used with Chama AI
CHAMA_AI_ACTION: false
# This event is used to send errors to the webhook
ERRORS: false
ERRORS_WEBHOOK: <url>
CONFIG_SESSION_PHONE:
# Name that will be displayed on smartphone connection
CLIENT: "Evolution API"
NAME: chrome # chrome | firefox | edge | opera | safari
NAME: Chrome # Chrome | Firefox | Edge | Opera | Safari
# Set qrcode display limit
QRCODE:
LIMIT: 30
COLOR: "#198754"
TYPEBOT:
API_VERSION: 'old' # old | latest
KEEP_OPEN: false
# Defines an authentication type for the api
# We recommend using the apikey because it will allow you to use a custom token,
@@ -137,4 +167,4 @@ AUTHENTICATION:
# Set the secret key to encrypt and decrypt your token and its expiration time.
JWT:
EXPIRIN_IN: 0 # seconds - 3600s === 1h | zero (0) - never expires
SECRET: L=0YWt]b2w[WF>#>:&E`
SECRET: L=0YWt]b2w[WF>#>:&E`

17
src/docs/swagger.conf.ts Normal file
View File

@@ -0,0 +1,17 @@
import { Router } from 'express';
import { join } from 'path';
import swaggerUi from 'swagger-ui-express';
import YAML from 'yamljs';
const document = YAML.load(join(process.cwd(), 'src', 'docs', 'swagger.yaml'));
const router = Router();
export const swaggerRouter = router.use('/docs', swaggerUi.serve).get(
'/docs',
swaggerUi.setup(document, {
customCssUrl: '/css/dark-theme-swagger.css',
customSiteTitle: 'Evolution API',
customfavIcon: '/images/logo.svg',
}),
);

2597
src/docs/swagger.yaml Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@ export class UnauthorizedException {
throw {
status: HttpStatus.UNAUTHORIZED,
error: 'Unauthorized',
message: objectError.length > 0 ? objectError : undefined,
message: objectError.length > 0 ? objectError : 'Unauthorized',
};
}
}

100
src/libs/amqp.server.ts Normal file
View File

@@ -0,0 +1,100 @@
import * as amqp from 'amqplib/callback_api';
import { configService, Rabbitmq } from '../config/env.config';
import { Logger } from '../config/logger.config';
const logger = new Logger('AMQP');
let amqpChannel: amqp.Channel | null = null;
export const initAMQP = () => {
return new Promise<void>((resolve, reject) => {
const uri = configService.get<Rabbitmq>('RABBITMQ').URI;
amqp.connect(uri, (error, connection) => {
if (error) {
reject(error);
return;
}
connection.createChannel((channelError, channel) => {
if (channelError) {
reject(channelError);
return;
}
const exchangeName = 'evolution_exchange';
channel.assertExchange(exchangeName, 'topic', {
durable: true,
autoDelete: false,
});
amqpChannel = channel;
logger.info('AMQP initialized');
resolve();
});
});
});
};
export const getAMQP = (): amqp.Channel | null => {
return amqpChannel;
};
export const initQueues = (instanceName: string, events: string[]) => {
if (!events || !events.length) return;
const queues = events.map((event) => {
return `${event.replace(/_/g, '.').toLowerCase()}`;
});
queues.forEach((event) => {
const amqp = getAMQP();
const exchangeName = instanceName ?? 'evolution_exchange';
amqp.assertExchange(exchangeName, 'topic', {
durable: true,
autoDelete: false,
});
const queueName = `${instanceName}.${event}`;
amqp.assertQueue(queueName, {
durable: true,
autoDelete: false,
arguments: {
'x-queue-type': 'quorum',
},
});
amqp.bindQueue(queueName, exchangeName, event);
});
};
export const removeQueues = (instanceName: string, events: string[]) => {
if (!events || !events.length) return;
const channel = getAMQP();
const queues = events.map((event) => {
return `${event.replace(/_/g, '.').toLowerCase()}`;
});
const exchangeName = instanceName ?? 'evolution_exchange';
queues.forEach((event) => {
const amqp = getAMQP();
amqp.assertExchange(exchangeName, 'topic', {
durable: true,
autoDelete: false,
});
const queueName = `${instanceName}.${event}`;
amqp.deleteQueue(queueName);
});
channel.deleteExchange(exchangeName);
};

View File

@@ -5,45 +5,55 @@ import { Redis } from '../config/env.config';
import { Logger } from '../config/logger.config';
export class RedisCache {
constructor() {
this.logger.verbose('instance created');
process.on('beforeExit', async () => {
this.logger.verbose('instance destroyed');
if (this.statusConnection) {
this.logger.verbose('instance disconnect');
await this.client.disconnect();
}
});
}
private readonly logger = new Logger(RedisCache.name);
private client: RedisClientType;
private statusConnection = false;
private instanceName: string;
private redisEnv: Redis;
constructor() {
this.logger.verbose('RedisCache instance created');
process.on('beforeExit', () => {
this.logger.verbose('RedisCache instance destroyed');
this.disconnect();
});
}
public set reference(reference: string) {
this.logger.verbose('set reference: ' + reference);
this.instanceName = reference;
}
public async connect(redisEnv: Redis) {
this.logger.verbose('connecting');
this.logger.verbose('Connecting to Redis...');
this.client = createClient({ url: redisEnv.URI });
this.logger.verbose('connected in ' + redisEnv.URI);
this.client.on('error', (err) => this.logger.error('Redis Client Error ' + err));
await this.client.connect();
this.statusConnection = true;
this.redisEnv = redisEnv;
this.logger.verbose(`Connected to ${redisEnv.URI}`);
}
private readonly logger = new Logger(RedisCache.name);
private client: RedisClientType;
public async disconnect() {
if (this.statusConnection) {
await this.client.disconnect();
this.statusConnection = false;
this.logger.verbose('Redis client disconnected');
}
}
public async instanceKeys(): Promise<string[]> {
const keys: string[] = [];
try {
this.logger.verbose('instance keys: ' + this.redisEnv.PREFIX_KEY + ':*');
return await this.client.sendCommand(['keys', this.redisEnv.PREFIX_KEY + ':*']);
this.logger.verbose('Fetching instance keys');
for await (const key of this.client.scanIterator({ MATCH: `${this.redisEnv.PREFIX_KEY}:*` })) {
keys.push(key);
}
} catch (error) {
this.logger.error(error);
this.logger.error('Error fetching instance keys ' + error);
}
return keys;
}
public async keyExists(key?: string) {

44
src/libs/socket.server.ts Normal file
View File

@@ -0,0 +1,44 @@
import { Server } from 'http';
import { Server as SocketIO } from 'socket.io';
import { configService, Cors, Websocket } from '../config/env.config';
import { Logger } from '../config/logger.config';
const logger = new Logger('Socket');
let io: SocketIO;
const cors = configService.get<Cors>('CORS').ORIGIN;
export const initIO = (httpServer: Server) => {
if (configService.get<Websocket>('WEBSOCKET')?.ENABLED) {
io = new SocketIO(httpServer, {
cors: {
origin: cors,
},
});
io.on('connection', (socket) => {
logger.info('User connected');
socket.on('disconnect', () => {
logger.info('User disconnected');
});
});
logger.info('Socket.io initialized');
return io;
}
return null;
};
export const getIO = (): SocketIO => {
logger.verbose('Getting Socket.io');
if (!io) {
logger.error('Socket.io not initialized');
throw new Error('Socket.io not initialized');
}
return io;
};

97
src/libs/sqs.server.ts Normal file
View File

@@ -0,0 +1,97 @@
import { SQS } from 'aws-sdk';
import { configService, Sqs } from '../config/env.config';
import { Logger } from '../config/logger.config';
const logger = new Logger('SQS');
let sqs: SQS;
export const initSQS = () => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
return new Promise<void>((resolve, reject) => {
const awsConfig = configService.get<Sqs>('SQS');
sqs = new SQS({
accessKeyId: awsConfig.ACCESS_KEY_ID,
secretAccessKey: awsConfig.SECRET_ACCESS_KEY,
region: awsConfig.REGION,
});
logger.info('SQS initialized');
resolve();
});
};
export const getSQS = (): SQS => {
return sqs;
};
export const initQueues = (instanceName: string, events: string[]) => {
if (!events || !events.length) return;
const queues = events.map((event) => {
return `${event.replace(/_/g, '_').toLowerCase()}`;
});
const sqs = getSQS();
queues.forEach((event) => {
const queueName = `${instanceName}_${event}.fifo`;
sqs.createQueue(
{
QueueName: queueName,
Attributes: {
FifoQueue: 'true',
},
},
(err, data) => {
if (err) {
logger.error(`Error creating queue ${queueName}: ${err.message}`);
} else {
logger.info(`Queue ${queueName} created: ${data.QueueUrl}`);
}
},
);
});
};
export const removeQueues = (instanceName: string, events: string[]) => {
if (!events || !events.length) return;
const sqs = getSQS();
const queues = events.map((event) => {
return `${event.replace(/_/g, '_').toLowerCase()}`;
});
queues.forEach((event) => {
const queueName = `${instanceName}_${event}.fifo`;
sqs.getQueueUrl(
{
QueueName: queueName,
},
(err, data) => {
if (err) {
logger.error(`Error getting queue URL for ${queueName}: ${err.message}`);
} else {
const queueUrl = data.QueueUrl;
sqs.deleteQueue(
{
QueueUrl: queueUrl,
},
(deleteErr) => {
if (deleteErr) {
logger.error(`Error deleting queue ${queueName}: ${deleteErr.message}`);
} else {
logger.info(`Queue ${queueName} deleted`);
}
},
);
}
},
);
});
};

View File

@@ -1,90 +1,138 @@
import 'express-async-errors';
import axios from 'axios';
import compression from 'compression';
import cors from 'cors';
import express, { json, NextFunction, Request, Response, urlencoded } from 'express';
import { join } from 'path';
import { configService, Cors, HttpServer } from './config/env.config';
import { Auth, configService, Cors, HttpServer, Rabbitmq, Sqs, Webhook } from './config/env.config';
import { onUnexpectedError } from './config/error.config';
import { Logger } from './config/logger.config';
import { ROOT_DIR } from './config/path.config';
import { swaggerRouter } from './docs/swagger.conf';
import { initAMQP } from './libs/amqp.server';
import { initIO } from './libs/socket.server';
import { initSQS } from './libs/sqs.server';
import { ServerUP } from './utils/server-up';
import { HttpStatus, router } from './whatsapp/routers/index.router';
import { waMonitor } from './whatsapp/whatsapp.module';
function initWA() {
waMonitor.loadInstance();
waMonitor.loadInstance();
}
function bootstrap() {
const logger = new Logger('SERVER');
const app = express();
const logger = new Logger('SERVER');
const app = express();
app.use(
cors({
origin(requestOrigin, callback) {
const { ORIGIN } = configService.get<Cors>('CORS');
!requestOrigin ? (requestOrigin = '*') : undefined;
if (ORIGIN.indexOf(requestOrigin) !== -1) {
return callback(null, true);
}
return callback(new Error('Not allowed by CORS'));
app.use(
cors({
origin(requestOrigin, callback) {
const { ORIGIN } = configService.get<Cors>('CORS');
if (ORIGIN.includes('*')) {
return callback(null, true);
}
if (ORIGIN.indexOf(requestOrigin) !== -1) {
return callback(null, true);
}
return callback(new Error('Not allowed by CORS'));
},
methods: [...configService.get<Cors>('CORS').METHODS],
credentials: configService.get<Cors>('CORS').CREDENTIALS,
}),
urlencoded({ extended: true, limit: '136mb' }),
json({ limit: '136mb' }),
compression(),
);
app.set('view engine', 'hbs');
app.set('views', join(ROOT_DIR, 'views'));
app.use(express.static(join(ROOT_DIR, 'public')));
app.use('/store', express.static(join(ROOT_DIR, 'store')));
app.use('/', router);
if (!configService.get('SERVER').DISABLE_DOCS) app.use(swaggerRouter);
app.use(
(err: Error, req: Request, res: Response, next: NextFunction) => {
if (err) {
const webhook = configService.get<Webhook>('WEBHOOK');
if (webhook.EVENTS.ERRORS_WEBHOOK && webhook.EVENTS.ERRORS_WEBHOOK != '' && webhook.EVENTS.ERRORS) {
const tzoffset = new Date().getTimezoneOffset() * 60000; //offset in milliseconds
const localISOTime = new Date(Date.now() - tzoffset).toISOString();
const now = localISOTime;
const globalApiKey = configService.get<Auth>('AUTHENTICATION').API_KEY.KEY;
const serverUrl = configService.get<HttpServer>('SERVER').URL;
const errorData = {
event: 'error',
data: {
error: err['error'] || 'Internal Server Error',
message: err['message'] || 'Internal Server Error',
status: err['status'] || 500,
response: {
message: err['message'] || 'Internal Server Error',
},
},
methods: [...configService.get<Cors>('CORS').METHODS],
credentials: configService.get<Cors>('CORS').CREDENTIALS,
}),
urlencoded({ extended: true, limit: '136mb' }),
json({ limit: '136mb' }),
compression(),
);
date_time: now,
api_key: globalApiKey,
server_url: serverUrl,
};
app.set('view engine', 'hbs');
app.set('views', join(ROOT_DIR, 'views'));
app.use(express.static(join(ROOT_DIR, 'public')));
logger.error(errorData);
app.use('/', router);
const baseURL = webhook.EVENTS.ERRORS_WEBHOOK;
const httpService = axios.create({ baseURL });
app.use(
(err: Error, req: Request, res: Response, next: NextFunction) => {
if (err) {
return res.status(err['status'] || 500).json({
status: 'ERROR',
error: err['error'] || 'Internal Server Error',
response: {
message: err['message'] || 'Internal Server Error',
},
}
);
}
httpService.post('', errorData);
}
next();
return res.status(err['status'] || 500).json({
status: err['status'] || 500,
error: err['error'] || 'Internal Server Error',
response: {
message: err['message'] || 'Internal Server Error',
},
});
}
next();
},
(req: Request, res: Response, next: NextFunction) => {
const { method, url } = req;
res.status(HttpStatus.NOT_FOUND).json({
status: HttpStatus.NOT_FOUND,
error: 'Not Found',
response: {
message: [`Cannot ${method.toUpperCase()} ${url}`],
},
(req: Request, res: Response, next: NextFunction) => {
const { method, url } = req;
});
res.status(HttpStatus.NOT_FOUND).json({
status: HttpStatus.NOT_FOUND,
error: 'Not Found',
response: {
message: `Cannot ${method.toUpperCase()} ${url}`,
},
});
next();
},
);
next();
},
);
const httpServer = configService.get<HttpServer>('SERVER');
const httpServer = configService.get<HttpServer>('SERVER');
ServerUP.app = app;
const server = ServerUP[httpServer.TYPE];
ServerUP.app = app;
const server = ServerUP[httpServer.TYPE];
server.listen(httpServer.PORT, () => logger.log(httpServer.TYPE.toUpperCase() + ' - ON: ' + httpServer.PORT));
server.listen(httpServer.PORT, () => logger.log(httpServer.TYPE.toUpperCase() + ' - ON: ' + httpServer.PORT));
initWA();
initWA();
initIO(server);
onUnexpectedError();
if (configService.get<Rabbitmq>('RABBITMQ')?.ENABLED) initAMQP();
if (configService.get<Sqs>('SQS')?.ENABLED) initSQS();
onUnexpectedError();
}
bootstrap();

View File

@@ -9,7 +9,7 @@ import {
import { configService, Database } from '../config/env.config';
import { Logger } from '../config/logger.config';
import { dbserver } from '../db/db.connect';
import { dbserver } from '../libs/db.connect';
export async function useMultiFileAuthStateDb(
coll: string,
@@ -25,7 +25,14 @@ export async function useMultiFileAuthStateDb(
const writeData = async (data: any, key: string): Promise<any> => {
try {
await client.connect();
return await collection.replaceOne({ _id: key }, JSON.parse(JSON.stringify(data, BufferJSON.replacer)), {
let msgParsed = JSON.parse(JSON.stringify(data, BufferJSON.replacer));
if (Array.isArray(msgParsed)) {
msgParsed = {
_id: key,
content_array: msgParsed,
};
}
return await collection.replaceOne({ _id: key }, msgParsed, {
upsert: true,
});
} catch (error) {
@@ -36,7 +43,10 @@ export async function useMultiFileAuthStateDb(
const readData = async (key: string): Promise<any> => {
try {
await client.connect();
const data = await collection.findOne({ _id: key });
let data = (await collection.findOne({ _id: key })) as any;
if (data?.content_array) {
data = data.content_array;
}
const creds = JSON.stringify(data);
return JSON.parse(creds, BufferJSON.reviver);
} catch (error) {
@@ -91,7 +101,7 @@ export async function useMultiFileAuthStateDb(
},
},
saveCreds: async () => {
return writeData(creds, 'creds');
return await writeData(creds, 'creds');
},
};
}

View File

@@ -7,7 +7,7 @@ import {
} from '@whiskeysockets/baileys';
import { Logger } from '../config/logger.config';
import { RedisCache } from '../db/redis.client';
import { RedisCache } from '../libs/redis.client';
export async function useMultiFileAuthStateRedisDb(cache: RedisCache): Promise<{
state: AuthenticationState;

View File

@@ -55,6 +55,9 @@ export const instanceNameSchema: JSONSchema7 = {
'CONNECTION_UPDATE',
'CALL',
'NEW_JWT_TOKEN',
'TYPEBOT_START',
'TYPEBOT_CHANGE_STATUS',
'CHAMA_AI_ACTION',
],
},
},
@@ -146,6 +149,16 @@ export const textMessageSchema: JSONSchema7 = {
required: ['textMessage', 'number'],
};
export const presenceSchema: JSONSchema7 = {
$id: v4(),
type: 'object',
properties: {
number: { ...numberDefinition },
options: { ...optionsSchema, required: ['presence', 'delay'] },
},
required: ['options', 'number'],
};
export const pollMessageSchema: JSONSchema7 = {
$id: v4(),
type: 'object',
@@ -508,6 +521,7 @@ export const archiveChatSchema: JSONSchema7 = {
$id: v4(),
type: 'object',
properties: {
chat: { type: 'string' },
lastMessage: {
type: 'object',
properties: {
@@ -528,7 +542,7 @@ export const archiveChatSchema: JSONSchema7 = {
},
archive: { type: 'boolean', enum: [true, false] },
},
required: ['lastMessage', 'archive'],
required: ['archive'],
};
export const deleteMessageSchema: JSONSchema7 = {
@@ -823,12 +837,86 @@ export const updateGroupDescriptionSchema: JSONSchema7 = {
...isNotEmpty('groupJid', 'description'),
};
// Webhook Schema
export const webhookSchema: JSONSchema7 = {
$id: v4(),
type: 'object',
properties: {
url: { type: 'string' },
events: {
type: 'array',
minItems: 0,
items: {
type: 'string',
enum: [
'APPLICATION_STARTUP',
'QRCODE_UPDATED',
'MESSAGES_SET',
'MESSAGES_UPSERT',
'MESSAGES_UPDATE',
'MESSAGES_DELETE',
'SEND_MESSAGE',
'CONTACTS_SET',
'CONTACTS_UPSERT',
'CONTACTS_UPDATE',
'PRESENCE_UPDATE',
'CHATS_SET',
'CHATS_UPSERT',
'CHATS_UPDATE',
'CHATS_DELETE',
'GROUPS_UPSERT',
'GROUP_UPDATE',
'GROUP_PARTICIPANTS_UPDATE',
'CONNECTION_UPDATE',
'CALL',
'NEW_JWT_TOKEN',
'TYPEBOT_START',
'TYPEBOT_CHANGE_STATUS',
'CHAMA_AI_ACTION',
],
},
},
},
required: ['url'],
...isNotEmpty('url'),
};
export const chatwootSchema: JSONSchema7 = {
$id: v4(),
type: 'object',
properties: {
enabled: { type: 'boolean', enum: [true, false] },
account_id: { type: 'string' },
token: { type: 'string' },
url: { type: 'string' },
sign_msg: { type: 'boolean', enum: [true, false] },
sign_delimiter: { type: ['string', 'null'] },
reopen_conversation: { type: 'boolean', enum: [true, false] },
conversation_pending: { type: 'boolean', enum: [true, false] },
auto_create: { type: 'boolean', enum: [true, false] },
},
required: ['enabled', 'account_id', 'token', 'url', 'sign_msg', 'reopen_conversation', 'conversation_pending'],
...isNotEmpty('account_id', 'token', 'url', 'sign_msg', 'reopen_conversation', 'conversation_pending'),
};
export const settingsSchema: JSONSchema7 = {
$id: v4(),
type: 'object',
properties: {
reject_call: { type: 'boolean', enum: [true, false] },
msg_call: { type: 'string' },
groups_ignore: { type: 'boolean', enum: [true, false] },
always_online: { type: 'boolean', enum: [true, false] },
read_messages: { type: 'boolean', enum: [true, false] },
read_status: { type: 'boolean', enum: [true, false] },
},
required: ['reject_call', 'groups_ignore', 'always_online', 'read_messages', 'read_status'],
...isNotEmpty('reject_call', 'groups_ignore', 'always_online', 'read_messages', 'read_status'),
};
export const websocketSchema: JSONSchema7 = {
$id: v4(),
type: 'object',
properties: {
enabled: { type: 'boolean', enum: [true, false] },
events: {
type: 'array',
@@ -857,41 +945,163 @@ export const webhookSchema: JSONSchema7 = {
'CONNECTION_UPDATE',
'CALL',
'NEW_JWT_TOKEN',
'TYPEBOT_START',
'TYPEBOT_CHANGE_STATUS',
'CHAMA_AI_ACTION',
],
},
},
},
required: ['url', 'enabled'],
...isNotEmpty('url'),
required: ['enabled'],
...isNotEmpty('enabled'),
};
export const chatwootSchema: JSONSchema7 = {
export const rabbitmqSchema: JSONSchema7 = {
$id: v4(),
type: 'object',
properties: {
enabled: { type: 'boolean', enum: [true, false] },
account_id: { type: 'string' },
token: { type: 'string' },
url: { type: 'string' },
sign_msg: { type: 'boolean', enum: [true, false] },
reopen_conversation: { type: 'boolean', enum: [true, false] },
conversation_pending: { type: 'boolean', enum: [true, false] },
events: {
type: 'array',
minItems: 0,
items: {
type: 'string',
enum: [
'APPLICATION_STARTUP',
'QRCODE_UPDATED',
'MESSAGES_SET',
'MESSAGES_UPSERT',
'MESSAGES_UPDATE',
'MESSAGES_DELETE',
'SEND_MESSAGE',
'CONTACTS_SET',
'CONTACTS_UPSERT',
'CONTACTS_UPDATE',
'PRESENCE_UPDATE',
'CHATS_SET',
'CHATS_UPSERT',
'CHATS_UPDATE',
'CHATS_DELETE',
'GROUPS_UPSERT',
'GROUP_UPDATE',
'GROUP_PARTICIPANTS_UPDATE',
'CONNECTION_UPDATE',
'CALL',
'NEW_JWT_TOKEN',
'TYPEBOT_START',
'TYPEBOT_CHANGE_STATUS',
'CHAMA_AI_ACTION',
],
},
},
},
required: ['enabled', 'account_id', 'token', 'url', 'sign_msg', 'reopen_conversation', 'conversation_pending'],
...isNotEmpty('account_id', 'token', 'url', 'sign_msg', 'reopen_conversation', 'conversation_pending'),
required: ['enabled'],
...isNotEmpty('enabled'),
};
export const settingsSchema: JSONSchema7 = {
export const sqsSchema: JSONSchema7 = {
$id: v4(),
type: 'object',
properties: {
reject_call: { type: 'boolean', enum: [true, false] },
msg_call: { type: 'string' },
groups_ignore: { type: 'boolean', enum: [true, false] },
always_online: { type: 'boolean', enum: [true, false] },
read_messages: { type: 'boolean', enum: [true, false] },
read_status: { type: 'boolean', enum: [true, false] },
enabled: { type: 'boolean', enum: [true, false] },
events: {
type: 'array',
minItems: 0,
items: {
type: 'string',
enum: [
'APPLICATION_STARTUP',
'QRCODE_UPDATED',
'MESSAGES_SET',
'MESSAGES_UPSERT',
'MESSAGES_UPDATE',
'MESSAGES_DELETE',
'SEND_MESSAGE',
'CONTACTS_SET',
'CONTACTS_UPSERT',
'CONTACTS_UPDATE',
'PRESENCE_UPDATE',
'CHATS_SET',
'CHATS_UPSERT',
'CHATS_UPDATE',
'CHATS_DELETE',
'GROUPS_UPSERT',
'GROUP_UPDATE',
'GROUP_PARTICIPANTS_UPDATE',
'CONNECTION_UPDATE',
'CALL',
'NEW_JWT_TOKEN',
'TYPEBOT_START',
'TYPEBOT_CHANGE_STATUS',
'CHAMA_AI_ACTION',
],
},
},
},
required: ['reject_call', 'groups_ignore', 'always_online', 'read_messages', 'read_status'],
...isNotEmpty('reject_call', 'groups_ignore', 'always_online', 'read_messages', 'read_status'),
required: ['enabled'],
...isNotEmpty('enabled'),
};
export const typebotSchema: JSONSchema7 = {
$id: v4(),
type: 'object',
properties: {
enabled: { type: 'boolean', enum: [true, false] },
url: { type: 'string' },
typebot: { type: 'string' },
expire: { type: 'integer' },
delay_message: { type: 'integer' },
unknown_message: { type: 'string' },
listening_from_me: { type: 'boolean', enum: [true, false] },
},
required: ['enabled', 'url', 'typebot', 'expire', 'delay_message', 'unknown_message', 'listening_from_me'],
...isNotEmpty('enabled', 'url', 'typebot', 'expire', 'delay_message', 'unknown_message', 'listening_from_me'),
};
export const typebotStatusSchema: JSONSchema7 = {
$id: v4(),
type: 'object',
properties: {
remoteJid: { type: 'string' },
status: { type: 'string', enum: ['opened', 'closed', 'paused'] },
},
required: ['remoteJid', 'status'],
...isNotEmpty('remoteJid', 'status'),
};
export const typebotStartSchema: JSONSchema7 = {
$id: v4(),
type: 'object',
properties: {
remoteJid: { type: 'string' },
url: { type: 'string' },
typebot: { type: 'string' },
},
required: ['remoteJid', 'url', 'typebot'],
...isNotEmpty('remoteJid', 'url', 'typebot'),
};
export const proxySchema: JSONSchema7 = {
$id: v4(),
type: 'object',
properties: {
enabled: { type: 'boolean', enum: [true, false] },
proxy: { type: 'string' },
},
required: ['enabled', 'proxy'],
...isNotEmpty('enabled', 'proxy'),
};
export const chamaaiSchema: JSONSchema7 = {
$id: v4(),
type: 'object',
properties: {
enabled: { type: 'boolean', enum: [true, false] },
url: { type: 'string' },
token: { type: 'string' },
waNumber: { type: 'string' },
answerByAudio: { type: 'boolean', enum: [true, false] },
},
required: ['enabled', 'url', 'token', 'waNumber', 'answerByAudio'],
...isNotEmpty('enabled', 'url', 'token', 'waNumber', 'answerByAudio'),
};

View File

@@ -48,20 +48,21 @@ export abstract class RouterBroker {
const v = schema ? validate(ref, schema) : { valid: true, errors: [] };
if (!v.valid) {
const message: any[] = v.errors.map(({ property, stack, schema }) => {
const message: any[] = v.errors.map(({ stack, schema }) => {
let message: string;
if (schema['description']) {
message = schema['description'];
} else {
message = stack.replace('instance.', '');
}
return {
property: property.replace('instance.', ''),
message,
};
return message;
// return {
// property: property.replace('instance.', ''),
// message,
// };
});
logger.error([...message]);
throw new BadRequestException(...message);
logger.error(message);
throw new BadRequestException(message);
}
return await execute(instance, ref);

View File

@@ -0,0 +1,29 @@
import { Logger } from '../../config/logger.config';
import { ChamaaiDto } from '../dto/chamaai.dto';
import { InstanceDto } from '../dto/instance.dto';
import { ChamaaiService } from '../services/chamaai.service';
const logger = new Logger('ChamaaiController');
export class ChamaaiController {
constructor(private readonly chamaaiService: ChamaaiService) {}
public async createChamaai(instance: InstanceDto, data: ChamaaiDto) {
logger.verbose('requested createChamaai from ' + instance.instanceName + ' instance');
if (!data.enabled) {
logger.verbose('chamaai disabled');
data.url = '';
data.token = '';
data.waNumber = '';
data.answerByAudio = false;
}
return this.chamaaiService.create(instance, data);
}
public async findChamaai(instance: InstanceDto) {
logger.verbose('requested findChamaai from ' + instance.instanceName + ' instance');
return this.chamaaiService.find(instance);
}
}

View File

@@ -9,6 +9,7 @@ import {
ProfilePictureDto,
ProfileStatusDto,
ReadMessageDto,
SendPresenceDto,
WhatsAppNumberDto,
} from '../dto/chat.dto';
import { InstanceDto } from '../dto/instance.dto';
@@ -77,6 +78,11 @@ export class ChatController {
return await this.waMonitor.waInstances[instanceName].fetchChats();
}
public async sendPresence({ instanceName }: InstanceDto, data: SendPresenceDto) {
logger.verbose('requested sendPresence from ' + instanceName + ' instance');
return await this.waMonitor.waInstances[instanceName].sendPresence(data);
}
public async fetchPrivacySettings({ instanceName }: InstanceDto) {
logger.verbose('requested fetchPrivacySettings from ' + instanceName + ' instance');
return await this.waMonitor.waInstances[instanceName].fetchPrivacySettings();

View File

@@ -5,13 +5,18 @@ import { Logger } from '../../config/logger.config';
import { BadRequestException } from '../../exceptions';
import { ChatwootDto } from '../dto/chatwoot.dto';
import { InstanceDto } from '../dto/instance.dto';
import { RepositoryBroker } from '../repository/repository.manager';
import { ChatwootService } from '../services/chatwoot.service';
import { waMonitor } from '../whatsapp.module';
const logger = new Logger('ChatwootController');
export class ChatwootController {
constructor(private readonly chatwootService: ChatwootService, private readonly configService: ConfigService) {}
constructor(
private readonly chatwootService: ChatwootService,
private readonly configService: ConfigService,
private readonly repository: RepositoryBroker,
) {}
public async createChatwoot(instance: InstanceDto, data: ChatwootDto) {
logger.verbose('requested createChatwoot from ' + instance.instanceName + ' instance');
@@ -32,6 +37,7 @@ export class ChatwootController {
if (data.sign_msg !== true && data.sign_msg !== false) {
throw new BadRequestException('sign_msg is required');
}
if (data.sign_msg === false) data.sign_delimiter = null;
}
if (!data.enabled) {
@@ -40,19 +46,21 @@ export class ChatwootController {
data.token = '';
data.url = '';
data.sign_msg = false;
data.sign_delimiter = null;
data.reopen_conversation = false;
data.conversation_pending = false;
data.auto_create = false;
}
data.name_inbox = instance.instanceName;
const result = this.chatwootService.create(instance, data);
const result = await this.chatwootService.create(instance, data);
const urlServer = this.configService.get<HttpServer>('SERVER').URL;
const response = {
...result,
webhook_url: `${urlServer}/chatwoot/webhook/${instance.instanceName}`,
webhook_url: `${urlServer}/chatwoot/webhook/${encodeURIComponent(instance.instanceName)}`,
};
return response;
@@ -64,7 +72,7 @@ export class ChatwootController {
const urlServer = this.configService.get<HttpServer>('SERVER').URL;
if (Object.keys(result).length === 0) {
if (Object.keys(result || {}).length === 0) {
return {
enabled: false,
url: '',
@@ -78,7 +86,7 @@ export class ChatwootController {
const response = {
...result,
webhook_url: `${urlServer}/chatwoot/webhook/${instance.instanceName}`,
webhook_url: `${urlServer}/chatwoot/webhook/${encodeURIComponent(instance.instanceName)}`,
};
return response;
@@ -86,14 +94,8 @@ export class ChatwootController {
public async receiveWebhook(instance: InstanceDto, data: any) {
logger.verbose('requested receiveWebhook from ' + instance.instanceName + ' instance');
const chatwootService = new ChatwootService(waMonitor, this.configService);
const chatwootService = new ChatwootService(waMonitor, this.configService, this.repository);
return chatwootService.receiveWebhook(instance, data);
}
public async newInstance(data: any) {
const chatwootService = new ChatwootService(waMonitor, this.configService);
return chatwootService.newInstance(data);
}
}

View File

@@ -1,20 +1,26 @@
import { delay } from '@whiskeysockets/baileys';
import { isURL } from 'class-validator';
import EventEmitter2 from 'eventemitter2';
import { v4 } from 'uuid';
import { ConfigService, HttpServer } from '../../config/env.config';
import { Logger } from '../../config/logger.config';
import { RedisCache } from '../../db/redis.client';
import { BadRequestException, InternalServerErrorException } from '../../exceptions';
import { RedisCache } from '../../libs/redis.client';
import { InstanceDto } from '../dto/instance.dto';
import { RepositoryBroker } from '../repository/repository.manager';
import { AuthService, OldToken } from '../services/auth.service';
import { ChatwootService } from '../services/chatwoot.service';
import { WAMonitoringService } from '../services/monitor.service';
import { ProxyService } from '../services/proxy.service';
import { RabbitmqService } from '../services/rabbitmq.service';
import { SettingsService } from '../services/settings.service';
import { SqsService } from '../services/sqs.service';
import { TypebotService } from '../services/typebot.service';
import { WebhookService } from '../services/webhook.service';
import { WebsocketService } from '../services/websocket.service';
import { WAStartupService } from '../services/whatsapp.service';
import { wa } from '../types/wa.types';
import { Events, wa } from '../types/wa.types';
export class InstanceController {
constructor(
@@ -26,6 +32,11 @@ export class InstanceController {
private readonly webhookService: WebhookService,
private readonly chatwootService: ChatwootService,
private readonly settingsService: SettingsService,
private readonly websocketService: WebsocketService,
private readonly rabbitmqService: RabbitmqService,
private readonly proxyService: ProxyService,
private readonly sqsService: SqsService,
private readonly typebotService: TypebotService,
private readonly cache: RedisCache,
) {}
@@ -35,6 +46,7 @@ export class InstanceController {
instanceName,
webhook,
webhook_by_events,
webhook_base64,
events,
qrcode,
number,
@@ -51,6 +63,20 @@ export class InstanceController {
always_online,
read_messages,
read_status,
websocket_enabled,
websocket_events,
rabbitmq_enabled,
rabbitmq_events,
sqs_enabled,
sqs_events,
typebot_url,
typebot,
typebot_expire,
typebot_keyword_finish,
typebot_delay_message,
typebot_unknown_message,
typebot_listening_from_me,
proxy,
}: InstanceDto) {
try {
this.logger.verbose('requested createInstance from ' + instanceName + ' instance');
@@ -62,6 +88,13 @@ export class InstanceController {
const instance = new WAStartupService(this.configService, this.eventEmitter, this.repository, this.cache);
instance.instanceName = instanceName;
const instanceId = v4();
instance.sendDataWebhook(Events.INSTANCE_CREATE, {
instanceName,
instanceId: instanceId,
});
this.logger.verbose('instance: ' + instance.instanceName + ' created');
this.waMonitor.waInstances[instance.instanceName] = instance;
@@ -71,13 +104,14 @@ export class InstanceController {
const hash = await this.authService.generateHash(
{
instanceName: instance.instanceName,
instanceId: instanceId,
},
token,
);
this.logger.verbose('hash: ' + hash + ' generated');
let getEvents: string[];
let webhookEvents: string[];
if (webhook) {
if (!isURL(webhook, { require_tld: false })) {
@@ -86,14 +120,226 @@ export class InstanceController {
this.logger.verbose('creating webhook');
try {
let newEvents: string[] = [];
if (events.length === 0) {
newEvents = [
'APPLICATION_STARTUP',
'QRCODE_UPDATED',
'MESSAGES_SET',
'MESSAGES_UPSERT',
'MESSAGES_UPDATE',
'MESSAGES_DELETE',
'SEND_MESSAGE',
'CONTACTS_SET',
'CONTACTS_UPSERT',
'CONTACTS_UPDATE',
'PRESENCE_UPDATE',
'CHATS_SET',
'CHATS_UPSERT',
'CHATS_UPDATE',
'CHATS_DELETE',
'GROUPS_UPSERT',
'GROUP_UPDATE',
'GROUP_PARTICIPANTS_UPDATE',
'CONNECTION_UPDATE',
'CALL',
'NEW_JWT_TOKEN',
'TYPEBOT_START',
'TYPEBOT_CHANGE_STATUS',
'CHAMA_AI_ACTION',
];
} else {
newEvents = events;
}
this.webhookService.create(instance, {
enabled: true,
url: webhook,
events,
events: newEvents,
webhook_by_events,
webhook_base64,
});
getEvents = (await this.webhookService.find(instance)).events;
webhookEvents = (await this.webhookService.find(instance)).events;
} catch (error) {
this.logger.log(error);
}
}
let websocketEvents: string[];
if (websocket_enabled) {
this.logger.verbose('creating websocket');
try {
let newEvents: string[] = [];
if (websocket_events.length === 0) {
newEvents = [
'APPLICATION_STARTUP',
'QRCODE_UPDATED',
'MESSAGES_SET',
'MESSAGES_UPSERT',
'MESSAGES_UPDATE',
'MESSAGES_DELETE',
'SEND_MESSAGE',
'CONTACTS_SET',
'CONTACTS_UPSERT',
'CONTACTS_UPDATE',
'PRESENCE_UPDATE',
'CHATS_SET',
'CHATS_UPSERT',
'CHATS_UPDATE',
'CHATS_DELETE',
'GROUPS_UPSERT',
'GROUP_UPDATE',
'GROUP_PARTICIPANTS_UPDATE',
'CONNECTION_UPDATE',
'CALL',
'NEW_JWT_TOKEN',
'TYPEBOT_START',
'TYPEBOT_CHANGE_STATUS',
'CHAMA_AI_ACTION',
];
} else {
newEvents = websocket_events;
}
this.websocketService.create(instance, {
enabled: true,
events: newEvents,
});
websocketEvents = (await this.websocketService.find(instance)).events;
} catch (error) {
this.logger.log(error);
}
}
let rabbitmqEvents: string[];
if (rabbitmq_enabled) {
this.logger.verbose('creating rabbitmq');
try {
let newEvents: string[] = [];
if (rabbitmq_events.length === 0) {
newEvents = [
'APPLICATION_STARTUP',
'QRCODE_UPDATED',
'MESSAGES_SET',
'MESSAGES_UPSERT',
'MESSAGES_UPDATE',
'MESSAGES_DELETE',
'SEND_MESSAGE',
'CONTACTS_SET',
'CONTACTS_UPSERT',
'CONTACTS_UPDATE',
'PRESENCE_UPDATE',
'CHATS_SET',
'CHATS_UPSERT',
'CHATS_UPDATE',
'CHATS_DELETE',
'GROUPS_UPSERT',
'GROUP_UPDATE',
'GROUP_PARTICIPANTS_UPDATE',
'CONNECTION_UPDATE',
'CALL',
'NEW_JWT_TOKEN',
'TYPEBOT_START',
'TYPEBOT_CHANGE_STATUS',
'CHAMA_AI_ACTION',
];
} else {
newEvents = rabbitmq_events;
}
this.rabbitmqService.create(instance, {
enabled: true,
events: newEvents,
});
rabbitmqEvents = (await this.rabbitmqService.find(instance)).events;
} catch (error) {
this.logger.log(error);
}
}
if (proxy) {
this.logger.verbose('creating proxy');
try {
this.proxyService.create(
instance,
{
enabled: true,
proxy,
},
false,
);
} catch (error) {
this.logger.log(error);
}
}
let sqsEvents: string[];
if (sqs_enabled) {
this.logger.verbose('creating sqs');
try {
let newEvents: string[] = [];
if (sqs_events.length === 0) {
newEvents = [
'APPLICATION_STARTUP',
'QRCODE_UPDATED',
'MESSAGES_SET',
'MESSAGES_UPSERT',
'MESSAGES_UPDATE',
'MESSAGES_DELETE',
'SEND_MESSAGE',
'CONTACTS_SET',
'CONTACTS_UPSERT',
'CONTACTS_UPDATE',
'PRESENCE_UPDATE',
'CHATS_SET',
'CHATS_UPSERT',
'CHATS_UPDATE',
'CHATS_DELETE',
'GROUPS_UPSERT',
'GROUP_UPDATE',
'GROUP_PARTICIPANTS_UPDATE',
'CONNECTION_UPDATE',
'CALL',
'NEW_JWT_TOKEN',
'TYPEBOT_START',
'TYPEBOT_CHANGE_STATUS',
'CHAMA_AI_ACTION',
];
} else {
newEvents = sqs_events;
}
this.sqsService.create(instance, {
enabled: true,
events: newEvents,
});
sqsEvents = (await this.sqsService.find(instance)).events;
} catch (error) {
this.logger.log(error);
}
}
if (typebot_url) {
try {
if (!isURL(typebot_url, { require_tld: false })) {
throw new BadRequestException('Invalid "url" property in typebot_url');
}
this.logger.verbose('creating typebot');
this.typebotService.create(instance, {
enabled: true,
url: typebot_url,
typebot: typebot,
expire: typebot_expire,
keyword_finish: typebot_keyword_finish,
delay_message: typebot_delay_message,
unknown_message: typebot_unknown_message,
listening_from_me: typebot_listening_from_me,
});
} catch (error) {
this.logger.log(error);
}
@@ -103,7 +349,7 @@ export class InstanceController {
const settings: wa.LocalSettings = {
reject_call: reject_call || false,
msg_call: msg_call || '',
groups_ignore: groups_ignore || false,
groups_ignore: groups_ignore || true,
always_online: always_online || false,
read_messages: read_messages || false,
read_status: read_status || false,
@@ -126,14 +372,41 @@ export class InstanceController {
const result = {
instance: {
instanceName: instance.instanceName,
instanceId: instanceId,
status: 'created',
},
hash,
webhook,
webhook_by_events,
events: getEvents,
webhook: {
webhook,
webhook_by_events,
webhook_base64,
events: webhookEvents,
},
websocket: {
enabled: websocket_enabled,
events: websocketEvents,
},
rabbitmq: {
enabled: rabbitmq_enabled,
events: rabbitmqEvents,
},
sqs: {
enabled: sqs_enabled,
events: sqsEvents,
},
typebot: {
enabled: typebot_url ? true : false,
url: typebot_url,
typebot,
expire: typebot_expire,
keyword_finish: typebot_keyword_finish,
delay_message: typebot_delay_message,
unknown_message: typebot_unknown_message,
listening_from_me: typebot_listening_from_me,
},
settings,
qrcode: getQrcode,
proxy,
};
this.logger.verbose('instance created');
@@ -179,19 +452,12 @@ export class InstanceController {
token: chatwoot_token,
url: chatwoot_url,
sign_msg: chatwoot_sign_msg || false,
name_inbox: instance.instanceName,
name_inbox: instance.instanceName.split('-cwId-')[0],
number,
reopen_conversation: chatwoot_reopen_conversation || false,
conversation_pending: chatwoot_conversation_pending || false,
auto_create: true,
});
this.chatwootService.initInstanceChatwoot(
instance,
instance.instanceName,
`${urlServer}/chatwoot/webhook/${instance.instanceName}`,
qrcode,
number,
);
} catch (error) {
this.logger.log(error);
}
@@ -199,12 +465,38 @@ export class InstanceController {
return {
instance: {
instanceName: instance.instanceName,
instanceId: instanceId,
status: 'created',
},
hash,
webhook,
webhook_by_events,
events: getEvents,
webhook: {
webhook,
webhook_by_events,
webhook_base64,
events: webhookEvents,
},
websocket: {
enabled: websocket_enabled,
events: websocketEvents,
},
rabbitmq: {
enabled: rabbitmq_enabled,
events: rabbitmqEvents,
},
sqs: {
enabled: sqs_enabled,
events: sqsEvents,
},
typebot: {
enabled: typebot_url ? true : false,
url: typebot_url,
typebot,
expire: typebot_expire,
keyword_finish: typebot_keyword_finish,
delay_message: typebot_delay_message,
unknown_message: typebot_unknown_message,
listening_from_me: typebot_listening_from_me,
},
settings,
chatwoot: {
enabled: true,
@@ -216,12 +508,13 @@ export class InstanceController {
conversation_pending: chatwoot_conversation_pending || false,
number,
name_inbox: instance.instanceName,
webhook_url: `${urlServer}/chatwoot/webhook/${instance.instanceName}`,
webhook_url: `${urlServer}/chatwoot/webhook/${encodeURIComponent(instance.instanceName)}`,
},
proxy,
};
} catch (error) {
console.log(error);
return { error: true, message: error.toString() };
this.logger.error(error.message[0]);
throw new BadRequestException(error.message[0]);
}
}
@@ -234,6 +527,10 @@ export class InstanceController {
this.logger.verbose('state: ' + state);
if (!state) {
throw new BadRequestException('The "' + instanceName + '" instance does not exist');
}
if (state == 'open') {
return await this.connectionState({ instanceName });
}
@@ -266,10 +563,19 @@ export class InstanceController {
try {
this.logger.verbose('requested restartInstance from ' + instanceName + ' instance');
this.logger.verbose('logging out instance: ' + instanceName);
this.waMonitor.waInstances[instanceName]?.client?.ws?.close();
const instance = this.waMonitor.waInstances[instanceName];
const state = instance?.connectionStatus?.state;
return { error: false, message: 'Instance restarted' };
switch (state) {
case 'open':
this.logger.verbose('logging out instance: ' + instanceName);
await instance.reloadConnection();
await delay(2000);
return await this.connectionState({ instanceName });
default:
return await this.connectionState({ instanceName });
}
} catch (error) {
this.logger.error(error);
}
@@ -285,13 +591,16 @@ export class InstanceController {
};
}
public async fetchInstances({ instanceName }: InstanceDto) {
this.logger.verbose('requested fetchInstances from ' + instanceName + ' instance');
public async fetchInstances({ instanceName, instanceId }: InstanceDto) {
if (instanceName) {
this.logger.verbose('requested fetchInstances from ' + instanceName + ' instance');
this.logger.verbose('instanceName: ' + instanceName);
return this.waMonitor.instanceInfo(instanceName);
} else if (instanceId) {
return this.waMonitor.instanceInfoById(instanceId);
}
this.logger.verbose('requested fetchInstances (all instances)');
return this.waMonitor.instanceInfo();
}
@@ -310,7 +619,7 @@ export class InstanceController {
this.logger.verbose('close connection instance: ' + instanceName);
this.waMonitor.waInstances[instanceName]?.client?.ws?.close();
return { error: false, message: 'Instance logged out' };
return { status: 'SUCCESS', error: false, response: { message: 'Instance logged out' } };
} catch (error) {
throw new InternalServerErrorException(error.toString());
}
@@ -324,19 +633,23 @@ export class InstanceController {
throw new BadRequestException('The "' + instanceName + '" instance needs to be disconnected');
}
try {
this.waMonitor.waInstances[instanceName]?.removeRabbitmqQueues();
if (instance.state === 'connecting') {
this.logger.verbose('logging out instance: ' + instanceName);
await this.logout({ instanceName });
delete this.waMonitor.waInstances[instanceName];
return { error: false, message: 'Instance deleted' };
} else {
this.logger.verbose('deleting instance: ' + instanceName);
delete this.waMonitor.waInstances[instanceName];
this.eventEmitter.emit('remove.instance', instanceName, 'inner');
return { error: false, message: 'Instance deleted' };
}
this.logger.verbose('deleting instance: ' + instanceName);
this.waMonitor.waInstances[instanceName].sendDataWebhook(Events.INSTANCE_DELETE, {
instanceName,
instanceId: (await this.repository.auth.find(instanceName))?.instanceId,
});
delete this.waMonitor.waInstances[instanceName];
this.eventEmitter.emit('remove.instance', instanceName, 'inner');
return { status: 'SUCCESS', error: false, response: { message: 'Instance deleted' } };
} catch (error) {
throw new BadRequestException(error.toString());
}

View File

@@ -0,0 +1,26 @@
import { Logger } from '../../config/logger.config';
import { InstanceDto } from '../dto/instance.dto';
import { ProxyDto } from '../dto/proxy.dto';
import { ProxyService } from '../services/proxy.service';
const logger = new Logger('ProxyController');
export class ProxyController {
constructor(private readonly proxyService: ProxyService) {}
public async createProxy(instance: InstanceDto, data: ProxyDto) {
logger.verbose('requested createProxy from ' + instance.instanceName + ' instance');
if (!data.enabled) {
logger.verbose('proxy disabled');
data.proxy = '';
}
return this.proxyService.create(instance, data);
}
public async findProxy(instance: InstanceDto) {
logger.verbose('requested findProxy from ' + instance.instanceName + ' instance');
return this.proxyService.find(instance);
}
}

View File

@@ -0,0 +1,56 @@
import { Logger } from '../../config/logger.config';
import { InstanceDto } from '../dto/instance.dto';
import { RabbitmqDto } from '../dto/rabbitmq.dto';
import { RabbitmqService } from '../services/rabbitmq.service';
const logger = new Logger('RabbitmqController');
export class RabbitmqController {
constructor(private readonly rabbitmqService: RabbitmqService) {}
public async createRabbitmq(instance: InstanceDto, data: RabbitmqDto) {
logger.verbose('requested createRabbitmq from ' + instance.instanceName + ' instance');
if (!data.enabled) {
logger.verbose('rabbitmq disabled');
data.events = [];
}
if (data.events.length === 0) {
logger.verbose('rabbitmq events empty');
data.events = [
'APPLICATION_STARTUP',
'QRCODE_UPDATED',
'MESSAGES_SET',
'MESSAGES_UPSERT',
'MESSAGES_UPDATE',
'MESSAGES_DELETE',
'SEND_MESSAGE',
'CONTACTS_SET',
'CONTACTS_UPSERT',
'CONTACTS_UPDATE',
'PRESENCE_UPDATE',
'CHATS_SET',
'CHATS_UPSERT',
'CHATS_UPDATE',
'CHATS_DELETE',
'GROUPS_UPSERT',
'GROUP_UPDATE',
'GROUP_PARTICIPANTS_UPDATE',
'CONNECTION_UPDATE',
'CALL',
'NEW_JWT_TOKEN',
'TYPEBOT_START',
'TYPEBOT_CHANGE_STATUS',
'CHAMA_AI_ACTION',
];
}
return this.rabbitmqService.create(instance, data);
}
public async findRabbitmq(instance: InstanceDto) {
logger.verbose('requested findRabbitmq from ' + instance.instanceName + ' instance');
return this.rabbitmqService.find(instance);
}
}

View File

@@ -19,6 +19,7 @@ export class SettingsController {
public async findSettings(instance: InstanceDto) {
logger.verbose('requested findSettings from ' + instance.instanceName + ' instance');
return this.settingsService.find(instance);
const settings = this.settingsService.find(instance);
return settings;
}
}

View File

@@ -0,0 +1,56 @@
import { Logger } from '../../config/logger.config';
import { InstanceDto } from '../dto/instance.dto';
import { SqsDto } from '../dto/sqs.dto';
import { SqsService } from '../services/sqs.service';
const logger = new Logger('SqsController');
export class SqsController {
constructor(private readonly sqsService: SqsService) {}
public async createSqs(instance: InstanceDto, data: SqsDto) {
logger.verbose('requested createSqs from ' + instance.instanceName + ' instance');
if (!data.enabled) {
logger.verbose('sqs disabled');
data.events = [];
}
if (data.events.length === 0) {
logger.verbose('sqs events empty');
data.events = [
'APPLICATION_STARTUP',
'QRCODE_UPDATED',
'MESSAGES_SET',
'MESSAGES_UPSERT',
'MESSAGES_UPDATE',
'MESSAGES_DELETE',
'SEND_MESSAGE',
'CONTACTS_SET',
'CONTACTS_UPSERT',
'CONTACTS_UPDATE',
'PRESENCE_UPDATE',
'CHATS_SET',
'CHATS_UPSERT',
'CHATS_UPDATE',
'CHATS_DELETE',
'GROUPS_UPSERT',
'GROUP_UPDATE',
'GROUP_PARTICIPANTS_UPDATE',
'CONNECTION_UPDATE',
'CALL',
'NEW_JWT_TOKEN',
'TYPEBOT_START',
'TYPEBOT_CHANGE_STATUS',
'CHAMA_AI_ACTION',
];
}
return this.sqsService.create(instance, data);
}
public async findSqs(instance: InstanceDto) {
logger.verbose('requested findSqs from ' + instance.instanceName + ' instance');
return this.sqsService.find(instance);
}
}

View File

@@ -0,0 +1,46 @@
import { Logger } from '../../config/logger.config';
import { InstanceDto } from '../dto/instance.dto';
import { TypebotDto } from '../dto/typebot.dto';
import { TypebotService } from '../services/typebot.service';
const logger = new Logger('TypebotController');
export class TypebotController {
constructor(private readonly typebotService: TypebotService) {}
public async createTypebot(instance: InstanceDto, data: TypebotDto) {
logger.verbose('requested createTypebot from ' + instance.instanceName + ' instance');
if (!data.enabled) {
logger.verbose('typebot disabled');
data.url = '';
data.typebot = '';
data.expire = 0;
data.sessions = [];
} else {
const saveData = await this.typebotService.find(instance);
if (saveData.enabled) {
logger.verbose('typebot enabled');
data.sessions = saveData.sessions;
}
}
return this.typebotService.create(instance, data);
}
public async findTypebot(instance: InstanceDto) {
logger.verbose('requested findTypebot from ' + instance.instanceName + ' instance');
return this.typebotService.find(instance);
}
public async changeStatus(instance: InstanceDto, data: any) {
logger.verbose('requested changeStatus from ' + instance.instanceName + ' instance');
return this.typebotService.changeStatus(instance, data);
}
public async startTypebot(instance: InstanceDto, data: any) {
logger.verbose('requested startTypebot from ' + instance.instanceName + ' instance');
return this.typebotService.startTypebot(instance, data);
}
}

View File

@@ -1,26 +0,0 @@
import { Request, Response } from 'express';
import { Auth, ConfigService } from '../../config/env.config';
import { BadRequestException } from '../../exceptions';
import { InstanceDto } from '../dto/instance.dto';
import { HttpStatus } from '../routers/index.router';
import { WAMonitoringService } from '../services/monitor.service';
export class ViewsController {
constructor(private readonly waMonit: WAMonitoringService, private readonly configService: ConfigService) {}
public async qrcode(request: Request, response: Response) {
try {
const param = request.params as unknown as InstanceDto;
const instance = this.waMonit.waInstances[param.instanceName];
if (instance.connectionStatus.state === 'open') {
throw new BadRequestException('The instance is already connected');
}
const type = this.configService.get<Auth>('AUTHENTICATION').TYPE;
return response.status(HttpStatus.OK).render('qrcode', { type, ...param });
} catch (error) {
console.log('ERROR: ', error);
}
}
}

View File

@@ -14,14 +14,44 @@ export class WebhookController {
public async createWebhook(instance: InstanceDto, data: WebhookDto) {
logger.verbose('requested createWebhook from ' + instance.instanceName + ' instance');
if (data.enabled && !isURL(data.url, { require_tld: false })) {
if (!isURL(data.url, { require_tld: false })) {
throw new BadRequestException('Invalid "url" property');
}
data.enabled = data.enabled ?? true;
if (!data.enabled) {
logger.verbose('webhook disabled');
data.url = '';
data.events = [];
} else if (data.events.length === 0) {
logger.verbose('webhook events empty');
data.events = [
'APPLICATION_STARTUP',
'QRCODE_UPDATED',
'MESSAGES_SET',
'MESSAGES_UPSERT',
'MESSAGES_UPDATE',
'MESSAGES_DELETE',
'SEND_MESSAGE',
'CONTACTS_SET',
'CONTACTS_UPSERT',
'CONTACTS_UPDATE',
'PRESENCE_UPDATE',
'CHATS_SET',
'CHATS_UPSERT',
'CHATS_UPDATE',
'CHATS_DELETE',
'GROUPS_UPSERT',
'GROUP_UPDATE',
'GROUP_PARTICIPANTS_UPDATE',
'CONNECTION_UPDATE',
'CALL',
'NEW_JWT_TOKEN',
'TYPEBOT_START',
'TYPEBOT_CHANGE_STATUS',
'CHAMA_AI_ACTION',
];
}
return this.webhookService.create(instance, data);

View File

@@ -0,0 +1,56 @@
import { Logger } from '../../config/logger.config';
import { InstanceDto } from '../dto/instance.dto';
import { WebsocketDto } from '../dto/websocket.dto';
import { WebsocketService } from '../services/websocket.service';
const logger = new Logger('WebsocketController');
export class WebsocketController {
constructor(private readonly websocketService: WebsocketService) {}
public async createWebsocket(instance: InstanceDto, data: WebsocketDto) {
logger.verbose('requested createWebsocket from ' + instance.instanceName + ' instance');
if (!data.enabled) {
logger.verbose('websocket disabled');
data.events = [];
}
if (data.events.length === 0) {
logger.verbose('websocket events empty');
data.events = [
'APPLICATION_STARTUP',
'QRCODE_UPDATED',
'MESSAGES_SET',
'MESSAGES_UPSERT',
'MESSAGES_UPDATE',
'MESSAGES_DELETE',
'SEND_MESSAGE',
'CONTACTS_SET',
'CONTACTS_UPSERT',
'CONTACTS_UPDATE',
'PRESENCE_UPDATE',
'CHATS_SET',
'CHATS_UPSERT',
'CHATS_UPDATE',
'CHATS_DELETE',
'GROUPS_UPSERT',
'GROUP_UPDATE',
'GROUP_PARTICIPANTS_UPDATE',
'CONNECTION_UPDATE',
'CALL',
'NEW_JWT_TOKEN',
'TYPEBOT_START',
'TYPEBOT_CHANGE_STATUS',
'CHAMA_AI_ACTION',
];
}
return this.websocketService.create(instance, data);
}
public async findWebsocket(instance: InstanceDto) {
logger.verbose('requested findWebsocket from ' + instance.instanceName + ' instance');
return this.websocketService.find(instance);
}
}

View File

@@ -0,0 +1,7 @@
export class ChamaaiDto {
enabled: boolean;
url: string;
token: string;
waNumber: string;
answerByAudio: boolean;
}

View File

@@ -1,4 +1,4 @@
import { proto, WAPrivacyOnlineValue, WAPrivacyValue, WAReadReceiptsValue } from '@whiskeysockets/baileys';
import { proto, WAPresence, WAPrivacyOnlineValue, WAPrivacyValue, WAReadReceiptsValue } from '@whiskeysockets/baileys';
export class OnWhatsAppDto {
constructor(public readonly jid: string, public readonly exists: boolean, public readonly name?: string) {}
@@ -53,13 +53,14 @@ export class ReadMessageDto {
read_messages: Key[];
}
class LastMessage {
export class LastMessage {
key: Key;
messageTimestamp?: number;
}
export class ArchiveChatDto {
lastMessage: LastMessage;
lastMessage?: LastMessage;
chat?: string;
archive: boolean;
}
@@ -82,3 +83,20 @@ export class DeleteMessage {
remoteJid: string;
participant?: string;
}
export class Options {
delay?: number;
presence?: WAPresence;
}
class OptionsMessage {
options: Options;
}
export class Metadata extends OptionsMessage {
number: string;
}
export class SendPresenceDto extends Metadata {
options: {
presence: WAPresence;
delay: number;
};
}

View File

@@ -5,7 +5,9 @@ export class ChatwootDto {
url?: string;
name_inbox?: string;
sign_msg?: boolean;
sign_delimiter?: string;
number?: string;
reopen_conversation?: boolean;
conversation_pending?: boolean;
auto_create?: boolean;
}

View File

@@ -1,10 +1,12 @@
export class InstanceDto {
instanceName: string;
instanceId?: string;
qrcode?: boolean;
number?: string;
token?: string;
webhook?: string;
webhook_by_events?: boolean;
webhook_base64?: boolean;
events?: string[];
reject_call?: boolean;
msg_call?: string;
@@ -18,4 +20,18 @@ export class InstanceDto {
chatwoot_sign_msg?: boolean;
chatwoot_reopen_conversation?: boolean;
chatwoot_conversation_pending?: boolean;
websocket_enabled?: boolean;
websocket_events?: string[];
rabbitmq_enabled?: boolean;
rabbitmq_events?: string[];
sqs_enabled?: boolean;
sqs_events?: string[];
typebot_url?: string;
typebot?: string;
typebot_expire?: number;
typebot_keyword_finish?: string;
typebot_delay_message?: number;
typebot_unknown_message?: string;
typebot_listening_from_me?: boolean;
proxy?: string;
}

View File

@@ -0,0 +1,4 @@
export class ProxyDto {
enabled: boolean;
proxy: string;
}

View File

@@ -0,0 +1,4 @@
export class RabbitmqDto {
enabled: boolean;
events?: string[];
}

View File

@@ -46,9 +46,13 @@ class PollMessage {
values: string[];
messageSecret?: Uint8Array;
}
export class SendTextDto extends Metadata {
textMessage: TextMessage;
}
export class SendPresence extends Metadata {
textMessage: TextMessage;
}
export class SendStatusDto extends Metadata {
statusMessage: StatusMessage;
@@ -61,6 +65,7 @@ export class SendPollDto extends Metadata {
export type MediaType = 'image' | 'document' | 'video' | 'audio';
export class MediaMessage {
mediatype: MediaType;
mimetype?: string;
caption?: string;
// for document
fileName?: string;

View File

@@ -0,0 +1,4 @@
export class SqsDto {
enabled: boolean;
events?: string[];
}

View File

@@ -0,0 +1,26 @@
export class Session {
remoteJid?: string;
sessionId?: string;
status?: string;
createdAt?: number;
updateAt?: number;
prefilledVariables?: PrefilledVariables;
}
export class PrefilledVariables {
remoteJid?: string;
pushName?: string;
additionalData?: { [key: string]: any };
}
export class TypebotDto {
enabled?: boolean;
url: string;
typebot?: string;
expire?: number;
keyword_finish?: string;
delay_message?: number;
unknown_message?: string;
listening_from_me?: boolean;
sessions?: Session[];
}

View File

@@ -3,4 +3,5 @@ export class WebhookDto {
url?: string;
events?: string[];
webhook_by_events?: boolean;
webhook_base64?: boolean;
}

View File

@@ -0,0 +1,4 @@
export class WebsocketDto {
enabled: boolean;
events?: string[];
}

View File

@@ -55,7 +55,7 @@ async function jwtGuard(req: Request, res: Response, next: NextFunction) {
}
}
async function apikey(req: Request, res: Response, next: NextFunction) {
async function apikey(req: Request, _: Response, next: NextFunction) {
const env = configService.get<Auth>('AUTHENTICATION').API_KEY;
const key = req.get('apikey');

View File

@@ -4,31 +4,40 @@ import { join } from 'path';
import { configService, Database, Redis } from '../../config/env.config';
import { INSTANCE_DIR } from '../../config/path.config';
import { dbserver } from '../../db/db.connect';
import { BadRequestException, ForbiddenException, NotFoundException } from '../../exceptions';
import {
BadRequestException,
ForbiddenException,
InternalServerErrorException,
NotFoundException,
} from '../../exceptions';
import { dbserver } from '../../libs/db.connect';
import { InstanceDto } from '../dto/instance.dto';
import { cache, waMonitor } from '../whatsapp.module';
async function getInstance(instanceName: string) {
const db = configService.get<Database>('DATABASE');
const redisConf = configService.get<Redis>('REDIS');
try {
const db = configService.get<Database>('DATABASE');
const redisConf = configService.get<Redis>('REDIS');
const exists = !!waMonitor.waInstances[instanceName];
const exists = !!waMonitor.waInstances[instanceName];
if (redisConf.ENABLED) {
const keyExists = await cache.keyExists();
return exists || keyExists;
if (redisConf.ENABLED) {
const keyExists = await cache.keyExists();
return exists || keyExists;
}
if (db.ENABLED) {
const collection = dbserver
.getClient()
.db(db.CONNECTION.DB_PREFIX_NAME + '-instances')
.collection(instanceName);
return exists || (await collection.find({}).toArray()).length > 0;
}
return exists || existsSync(join(INSTANCE_DIR, instanceName));
} catch (error) {
throw new InternalServerErrorException(error?.toString());
}
if (db.ENABLED) {
const collection = dbserver
.getClient()
.db(db.CONNECTION.DB_PREFIX_NAME + '-instances')
.collection(instanceName);
return exists || (await collection.find({}).toArray()).length > 0;
}
return exists || existsSync(join(INSTANCE_DIR, instanceName));
}
export async function instanceExistsGuard(req: Request, _: Response, next: NextFunction) {
@@ -56,6 +65,7 @@ export async function instanceLoggedGuard(req: Request, _: Response, next: NextF
}
if (waMonitor.waInstances[instance.instanceName]) {
waMonitor.waInstances[instance.instanceName]?.removeRabbitmqQueues();
delete waMonitor.waInstances[instance.instanceName];
}
}

View File

@@ -1,17 +1,19 @@
import { Schema } from 'mongoose';
import { dbserver } from '../../db/db.connect';
import { dbserver } from '../../libs/db.connect';
export class AuthRaw {
_id?: string;
jwt?: string;
apikey?: string;
instanceId?: string;
}
const authSchema = new Schema<AuthRaw>({
_id: { type: String, _id: true },
jwt: { type: String, minlength: 1 },
apikey: { type: String, minlength: 1 },
instanceId: { type: String, minlength: 1 },
});
export const AuthModel = dbserver?.model(AuthRaw.name, authSchema, 'authentication');

View File

@@ -0,0 +1,24 @@
import { Schema } from 'mongoose';
import { dbserver } from '../../libs/db.connect';
export class ChamaaiRaw {
_id?: string;
enabled?: boolean;
url?: string;
token?: string;
waNumber?: string;
answerByAudio?: boolean;
}
const chamaaiSchema = new Schema<ChamaaiRaw>({
_id: { type: String, _id: true },
enabled: { type: Boolean, required: true },
url: { type: String, required: true },
token: { type: String, required: true },
waNumber: { type: String, required: true },
answerByAudio: { type: Boolean, required: true },
});
export const ChamaaiModel = dbserver?.model(ChamaaiRaw.name, chamaaiSchema, 'chamaai');
export type IChamaaiModel = typeof ChamaaiModel;

View File

@@ -1,6 +1,6 @@
import { Schema } from 'mongoose';
import { dbserver } from '../../db/db.connect';
import { dbserver } from '../../libs/db.connect';
export class ChatRaw {
_id?: string;

View File

@@ -1,6 +1,6 @@
import { Schema } from 'mongoose';
import { dbserver } from '../../db/db.connect';
import { dbserver } from '../../libs/db.connect';
export class ChatwootRaw {
_id?: string;
@@ -10,6 +10,7 @@ export class ChatwootRaw {
url?: string;
name_inbox?: string;
sign_msg?: boolean;
sign_delimiter?: string;
number?: string;
reopen_conversation?: boolean;
conversation_pending?: boolean;
@@ -23,7 +24,10 @@ const chatwootSchema = new Schema<ChatwootRaw>({
url: { type: String, required: true },
name_inbox: { type: String, required: true },
sign_msg: { type: Boolean, required: true },
sign_delimiter: { type: String, required: false },
number: { type: String, required: true },
reopen_conversation: { type: Boolean, required: true },
conversation_pending: { type: Boolean, required: true },
});
export const ChatwootModel = dbserver?.model(ChatwootRaw.name, chatwootSchema, 'chatwoot');

View File

@@ -1,6 +1,6 @@
import { Schema } from 'mongoose';
import { dbserver } from '../../db/db.connect';
import { dbserver } from '../../libs/db.connect';
export class ContactRaw {
_id?: string;

View File

@@ -1,7 +1,13 @@
export * from './auth.model';
export * from './chamaai.model';
export * from './chat.model';
export * from './chatwoot.model';
export * from './contact.model';
export * from './message.model';
export * from './proxy.model';
export * from './rabbitmq.model';
export * from './settings.model';
export * from './sqs.model';
export * from './typebot.model';
export * from './webhook.model';
export * from './websocket.model';

View File

@@ -1,6 +1,6 @@
import { Schema } from 'mongoose';
import { dbserver } from '../../db/db.connect';
import { dbserver } from '../../libs/db.connect';
import { wa } from '../types/wa.types';
class Key {
@@ -10,6 +10,12 @@ class Key {
participant?: string;
}
class ChatwootMessage {
messageId?: number;
inboxId?: number;
conversationId?: number;
}
export class MessageRaw {
_id?: string;
key?: Key;
@@ -20,6 +26,9 @@ export class MessageRaw {
messageTimestamp?: number | Long.Long;
owner: string;
source?: 'android' | 'web' | 'ios';
source_id?: string;
source_reply_id?: string;
chatwoot?: ChatwootMessage;
}
const messageSchema = new Schema<MessageRaw>({
@@ -37,8 +46,18 @@ const messageSchema = new Schema<MessageRaw>({
source: { type: String, minlength: 3, enum: ['android', 'web', 'ios'] },
messageTimestamp: { type: Number, required: true },
owner: { type: String, required: true, minlength: 1 },
chatwoot: {
messageId: { type: Number },
inboxId: { type: Number },
conversationId: { type: Number },
},
});
messageSchema.index({ 'chatwoot.messageId': 1, owner: 1 });
messageSchema.index({ 'key.id': 1 });
messageSchema.index({ 'key.id': 1, owner: 1 });
messageSchema.index({ owner: 1 });
export const MessageModel = dbserver?.model(MessageRaw.name, messageSchema, 'messages');
export type IMessageModel = typeof MessageModel;

View File

@@ -0,0 +1,18 @@
import { Schema } from 'mongoose';
import { dbserver } from '../../libs/db.connect';
export class ProxyRaw {
_id?: string;
enabled?: boolean;
proxy?: string;
}
const proxySchema = new Schema<ProxyRaw>({
_id: { type: String, _id: true },
enabled: { type: Boolean, required: true },
proxy: { type: String, required: true },
});
export const ProxyModel = dbserver?.model(ProxyRaw.name, proxySchema, 'proxy');
export type IProxyModel = typeof ProxyModel;

View File

@@ -0,0 +1,18 @@
import { Schema } from 'mongoose';
import { dbserver } from '../../libs/db.connect';
export class RabbitmqRaw {
_id?: string;
enabled?: boolean;
events?: string[];
}
const rabbitmqSchema = new Schema<RabbitmqRaw>({
_id: { type: String, _id: true },
enabled: { type: Boolean, required: true },
events: { type: [String], required: true },
});
export const RabbitmqModel = dbserver?.model(RabbitmqRaw.name, rabbitmqSchema, 'rabbitmq');
export type IRabbitmqModel = typeof RabbitmqModel;

View File

@@ -1,6 +1,6 @@
import { Schema } from 'mongoose';
import { dbserver } from '../../db/db.connect';
import { dbserver } from '../../libs/db.connect';
export class SettingsRaw {
_id?: string;

View File

@@ -0,0 +1,18 @@
import { Schema } from 'mongoose';
import { dbserver } from '../../libs/db.connect';
export class SqsRaw {
_id?: string;
enabled?: boolean;
events?: string[];
}
const sqsSchema = new Schema<SqsRaw>({
_id: { type: String, _id: true },
enabled: { type: Boolean, required: true },
events: { type: [String], required: true },
});
export const SqsModel = dbserver?.model(SqsRaw.name, sqsSchema, 'sqs');
export type ISqsModel = typeof SqsModel;

View File

@@ -0,0 +1,58 @@
import { Schema } from 'mongoose';
import { dbserver } from '../../libs/db.connect';
class Session {
remoteJid?: string;
sessionId?: string;
status?: string;
createdAt?: number;
updateAt?: number;
prefilledVariables?: {
remoteJid?: string;
pushName?: string;
additionalData?: { [key: string]: any };
};
}
export class TypebotRaw {
_id?: string;
enabled?: boolean;
url: string;
typebot?: string;
expire?: number;
keyword_finish?: string;
delay_message?: number;
unknown_message?: string;
listening_from_me?: boolean;
sessions?: Session[];
}
const typebotSchema = new Schema<TypebotRaw>({
_id: { type: String, _id: true },
enabled: { type: Boolean, required: true },
url: { type: String, required: true },
typebot: { type: String, required: true },
expire: { type: Number, required: true },
keyword_finish: { type: String, required: true },
delay_message: { type: Number, required: true },
unknown_message: { type: String, required: true },
listening_from_me: { type: Boolean, required: true },
sessions: [
{
remoteJid: { type: String, required: true },
sessionId: { type: String, required: true },
status: { type: String, required: true },
createdAt: { type: Number, required: true },
updateAt: { type: Number, required: true },
prefilledVariables: {
remoteJid: { type: String, required: false },
pushName: { type: String, required: false },
additionalData: { type: Schema.Types.Mixed, required: false },
},
},
],
});
export const TypebotModel = dbserver?.model(TypebotRaw.name, typebotSchema, 'typebot');
export type ITypebotModel = typeof TypebotModel;

View File

@@ -1,6 +1,6 @@
import { Schema } from 'mongoose';
import { dbserver } from '../../db/db.connect';
import { dbserver } from '../../libs/db.connect';
export class WebhookRaw {
_id?: string;
@@ -8,6 +8,7 @@ export class WebhookRaw {
enabled?: boolean;
events?: string[];
webhook_by_events?: boolean;
webhook_base64?: boolean;
}
const webhookSchema = new Schema<WebhookRaw>({
@@ -16,6 +17,7 @@ const webhookSchema = new Schema<WebhookRaw>({
enabled: { type: Boolean, required: true },
events: { type: [String], required: true },
webhook_by_events: { type: Boolean, required: true },
webhook_base64: { type: Boolean, required: true },
});
export const WebhookModel = dbserver?.model(WebhookRaw.name, webhookSchema, 'webhook');

View File

@@ -0,0 +1,18 @@
import { Schema } from 'mongoose';
import { dbserver } from '../../libs/db.connect';
export class WebsocketRaw {
_id?: string;
enabled?: boolean;
events?: string[];
}
const websocketSchema = new Schema<WebsocketRaw>({
_id: { type: String, _id: true },
enabled: { type: Boolean, required: true },
events: { type: [String], required: true },
});
export const WebsocketModel = dbserver?.model(WebsocketRaw.name, websocketSchema, 'websocket');
export type IWebsocketModel = typeof WebsocketModel;

View File

@@ -19,6 +19,7 @@ export class AuthRepository extends Repository {
public async create(data: AuthRaw, instance: string): Promise<IInsert> {
try {
this.logger.verbose('creating auth');
if (this.dbSettings.ENABLED) {
this.logger.verbose('saving auth to db');
const insert = await this.authModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
@@ -62,4 +63,20 @@ export class AuthRepository extends Repository {
return {};
}
}
public async findInstanceNameById(instanceId: string): Promise<string | null> {
try {
this.logger.verbose('finding auth by instanceId');
if (this.dbSettings.ENABLED) {
this.logger.verbose('finding auth in db');
const response = await this.authModel.findOne({ instanceId });
return response._id;
}
this.logger.verbose('finding auth in store is not supported');
} catch (error) {
return null;
}
}
}

View File

@@ -0,0 +1,62 @@
import { readFileSync } from 'fs';
import { join } from 'path';
import { ConfigService } from '../../config/env.config';
import { Logger } from '../../config/logger.config';
import { IInsert, Repository } from '../abstract/abstract.repository';
import { ChamaaiRaw, IChamaaiModel } from '../models';
export class ChamaaiRepository extends Repository {
constructor(private readonly chamaaiModel: IChamaaiModel, private readonly configService: ConfigService) {
super(configService);
}
private readonly logger = new Logger('ChamaaiRepository');
public async create(data: ChamaaiRaw, instance: string): Promise<IInsert> {
try {
this.logger.verbose('creating chamaai');
if (this.dbSettings.ENABLED) {
this.logger.verbose('saving chamaai to db');
const insert = await this.chamaaiModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
this.logger.verbose('chamaai saved to db: ' + insert.modifiedCount + ' chamaai');
return { insertCount: insert.modifiedCount };
}
this.logger.verbose('saving chamaai to store');
this.writeStore<ChamaaiRaw>({
path: join(this.storePath, 'chamaai'),
fileName: instance,
data,
});
this.logger.verbose('chamaai saved to store in path: ' + join(this.storePath, 'chamaai') + '/' + instance);
this.logger.verbose('chamaai created');
return { insertCount: 1 };
} catch (error) {
return error;
}
}
public async find(instance: string): Promise<ChamaaiRaw> {
try {
this.logger.verbose('finding chamaai');
if (this.dbSettings.ENABLED) {
this.logger.verbose('finding chamaai in db');
return await this.chamaaiModel.findOne({ _id: instance });
}
this.logger.verbose('finding chamaai in store');
return JSON.parse(
readFileSync(join(this.storePath, 'chamaai', instance + '.json'), {
encoding: 'utf-8',
}),
) as ChamaaiRaw;
} catch (error) {
return {};
}
}
}

View File

@@ -91,11 +91,13 @@ export class MessageRepository extends Repository {
this.logger.verbose('finding messages');
if (this.dbSettings.ENABLED) {
this.logger.verbose('finding messages in db');
if (query?.where?.key) {
for (const [k, v] of Object.entries(query.where.key)) {
query.where['key.' + k] = v;
for (const [o, p] of Object.entries(query?.where)) {
if (typeof p === 'object' && p !== null && !Array.isArray(p)) {
for (const [k, v] of Object.entries(p)) {
query.where[`${o}.${k}`] = v;
}
delete query.where[o];
}
delete query?.where?.key;
}
return await this.messageModel
@@ -144,4 +146,55 @@ export class MessageRepository extends Repository {
return [];
}
}
public async update(data: MessageRaw[], instanceName: string, saveDb?: boolean): Promise<IInsert> {
try {
if (this.dbSettings.ENABLED && saveDb) {
this.logger.verbose('updating messages in db');
const messages = data.map((message) => {
return {
updateOne: {
filter: { 'key.id': message.key.id },
update: { ...message },
},
};
});
const { nModified } = await this.messageModel.bulkWrite(messages);
this.logger.verbose('messages updated in db: ' + nModified + ' messages');
return { insertCount: nModified };
}
this.logger.verbose('updating messages in store');
const store = this.configService.get<StoreConf>('STORE');
if (store.MESSAGES) {
this.logger.verbose('updating messages in store');
data.forEach((message) => {
this.writeStore({
path: join(this.storePath, 'messages', instanceName),
fileName: message.key.id,
data: message,
});
this.logger.verbose(
'messages updated in store in path: ' +
join(this.storePath, 'messages', instanceName) +
'/' +
message.key.id,
);
});
this.logger.verbose('messages updated in store: ' + data.length + ' messages');
return { insertCount: data.length };
}
this.logger.verbose('messages not updated');
return { insertCount: 0 };
} catch (error) {
this.logger.error(error);
}
}
}

View File

@@ -0,0 +1,62 @@
import { readFileSync } from 'fs';
import { join } from 'path';
import { ConfigService } from '../../config/env.config';
import { Logger } from '../../config/logger.config';
import { IInsert, Repository } from '../abstract/abstract.repository';
import { IProxyModel, ProxyRaw } from '../models';
export class ProxyRepository extends Repository {
constructor(private readonly proxyModel: IProxyModel, private readonly configService: ConfigService) {
super(configService);
}
private readonly logger = new Logger('ProxyRepository');
public async create(data: ProxyRaw, instance: string): Promise<IInsert> {
try {
this.logger.verbose('creating proxy');
if (this.dbSettings.ENABLED) {
this.logger.verbose('saving proxy to db');
const insert = await this.proxyModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
this.logger.verbose('proxy saved to db: ' + insert.modifiedCount + ' proxy');
return { insertCount: insert.modifiedCount };
}
this.logger.verbose('saving proxy to store');
this.writeStore<ProxyRaw>({
path: join(this.storePath, 'proxy'),
fileName: instance,
data,
});
this.logger.verbose('proxy saved to store in path: ' + join(this.storePath, 'proxy') + '/' + instance);
this.logger.verbose('proxy created');
return { insertCount: 1 };
} catch (error) {
return error;
}
}
public async find(instance: string): Promise<ProxyRaw> {
try {
this.logger.verbose('finding proxy');
if (this.dbSettings.ENABLED) {
this.logger.verbose('finding proxy in db');
return await this.proxyModel.findOne({ _id: instance });
}
this.logger.verbose('finding proxy in store');
return JSON.parse(
readFileSync(join(this.storePath, 'proxy', instance + '.json'), {
encoding: 'utf-8',
}),
) as ProxyRaw;
} catch (error) {
return {};
}
}
}

View File

@@ -0,0 +1,62 @@
import { readFileSync } from 'fs';
import { join } from 'path';
import { ConfigService } from '../../config/env.config';
import { Logger } from '../../config/logger.config';
import { IInsert, Repository } from '../abstract/abstract.repository';
import { IRabbitmqModel, RabbitmqRaw } from '../models';
export class RabbitmqRepository extends Repository {
constructor(private readonly rabbitmqModel: IRabbitmqModel, private readonly configService: ConfigService) {
super(configService);
}
private readonly logger = new Logger('RabbitmqRepository');
public async create(data: RabbitmqRaw, instance: string): Promise<IInsert> {
try {
this.logger.verbose('creating rabbitmq');
if (this.dbSettings.ENABLED) {
this.logger.verbose('saving rabbitmq to db');
const insert = await this.rabbitmqModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
this.logger.verbose('rabbitmq saved to db: ' + insert.modifiedCount + ' rabbitmq');
return { insertCount: insert.modifiedCount };
}
this.logger.verbose('saving rabbitmq to store');
this.writeStore<RabbitmqRaw>({
path: join(this.storePath, 'rabbitmq'),
fileName: instance,
data,
});
this.logger.verbose('rabbitmq saved to store in path: ' + join(this.storePath, 'rabbitmq') + '/' + instance);
this.logger.verbose('rabbitmq created');
return { insertCount: 1 };
} catch (error) {
return error;
}
}
public async find(instance: string): Promise<RabbitmqRaw> {
try {
this.logger.verbose('finding rabbitmq');
if (this.dbSettings.ENABLED) {
this.logger.verbose('finding rabbitmq in db');
return await this.rabbitmqModel.findOne({ _id: instance });
}
this.logger.verbose('finding rabbitmq in store');
return JSON.parse(
readFileSync(join(this.storePath, 'rabbitmq', instance + '.json'), {
encoding: 'utf-8',
}),
) as RabbitmqRaw;
} catch (error) {
return {};
}
}
}

View File

@@ -5,13 +5,19 @@ import { join } from 'path';
import { Auth, ConfigService, Database } from '../../config/env.config';
import { Logger } from '../../config/logger.config';
import { AuthRepository } from './auth.repository';
import { ChamaaiRepository } from './chamaai.repository';
import { ChatRepository } from './chat.repository';
import { ChatwootRepository } from './chatwoot.repository';
import { ContactRepository } from './contact.repository';
import { MessageRepository } from './message.repository';
import { MessageUpRepository } from './messageUp.repository';
import { ProxyRepository } from './proxy.repository';
import { RabbitmqRepository } from './rabbitmq.repository';
import { SettingsRepository } from './settings.repository';
import { SqsRepository } from './sqs.repository';
import { TypebotRepository } from './typebot.repository';
import { WebhookRepository } from './webhook.repository';
import { WebsocketRepository } from './websocket.repository';
export class RepositoryBroker {
constructor(
public readonly message: MessageRepository,
@@ -21,6 +27,12 @@ export class RepositoryBroker {
public readonly webhook: WebhookRepository,
public readonly chatwoot: ChatwootRepository,
public readonly settings: SettingsRepository,
public readonly websocket: WebsocketRepository,
public readonly rabbitmq: RabbitmqRepository,
public readonly sqs: SqsRepository,
public readonly typebot: TypebotRepository,
public readonly proxy: ProxyRepository,
public readonly chamaai: ChamaaiRepository,
public readonly auth: AuthRepository,
private configService: ConfigService,
dbServer?: MongoClient,
@@ -51,6 +63,12 @@ export class RepositoryBroker {
const webhookDir = join(storePath, 'webhook');
const chatwootDir = join(storePath, 'chatwoot');
const settingsDir = join(storePath, 'settings');
const websocketDir = join(storePath, 'websocket');
const rabbitmqDir = join(storePath, 'rabbitmq');
const sqsDir = join(storePath, 'sqs');
const typebotDir = join(storePath, 'typebot');
const proxyDir = join(storePath, 'proxy');
const chamaaiDir = join(storePath, 'chamaai');
const tempDir = join(storePath, 'temp');
if (!fs.existsSync(authDir)) {
@@ -85,6 +103,30 @@ export class RepositoryBroker {
this.logger.verbose('creating settings dir: ' + settingsDir);
fs.mkdirSync(settingsDir, { recursive: true });
}
if (!fs.existsSync(websocketDir)) {
this.logger.verbose('creating websocket dir: ' + websocketDir);
fs.mkdirSync(websocketDir, { recursive: true });
}
if (!fs.existsSync(rabbitmqDir)) {
this.logger.verbose('creating rabbitmq dir: ' + rabbitmqDir);
fs.mkdirSync(rabbitmqDir, { recursive: true });
}
if (!fs.existsSync(sqsDir)) {
this.logger.verbose('creating sqs dir: ' + sqsDir);
fs.mkdirSync(sqsDir, { recursive: true });
}
if (!fs.existsSync(typebotDir)) {
this.logger.verbose('creating typebot dir: ' + typebotDir);
fs.mkdirSync(typebotDir, { recursive: true });
}
if (!fs.existsSync(proxyDir)) {
this.logger.verbose('creating proxy dir: ' + proxyDir);
fs.mkdirSync(proxyDir, { recursive: true });
}
if (!fs.existsSync(chamaaiDir)) {
this.logger.verbose('creating chamaai dir: ' + chamaaiDir);
fs.mkdirSync(chamaaiDir, { recursive: true });
}
if (!fs.existsSync(tempDir)) {
this.logger.verbose('creating temp dir: ' + tempDir);
fs.mkdirSync(tempDir, { recursive: true });

View File

@@ -0,0 +1,62 @@
import { readFileSync } from 'fs';
import { join } from 'path';
import { ConfigService } from '../../config/env.config';
import { Logger } from '../../config/logger.config';
import { IInsert, Repository } from '../abstract/abstract.repository';
import { ISqsModel, SqsRaw } from '../models';
export class SqsRepository extends Repository {
constructor(private readonly sqsModel: ISqsModel, private readonly configService: ConfigService) {
super(configService);
}
private readonly logger = new Logger('SqsRepository');
public async create(data: SqsRaw, instance: string): Promise<IInsert> {
try {
this.logger.verbose('creating sqs');
if (this.dbSettings.ENABLED) {
this.logger.verbose('saving sqs to db');
const insert = await this.sqsModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
this.logger.verbose('sqs saved to db: ' + insert.modifiedCount + ' sqs');
return { insertCount: insert.modifiedCount };
}
this.logger.verbose('saving sqs to store');
this.writeStore<SqsRaw>({
path: join(this.storePath, 'sqs'),
fileName: instance,
data,
});
this.logger.verbose('sqs saved to store in path: ' + join(this.storePath, 'sqs') + '/' + instance);
this.logger.verbose('sqs created');
return { insertCount: 1 };
} catch (error) {
return error;
}
}
public async find(instance: string): Promise<SqsRaw> {
try {
this.logger.verbose('finding sqs');
if (this.dbSettings.ENABLED) {
this.logger.verbose('finding sqs in db');
return await this.sqsModel.findOne({ _id: instance });
}
this.logger.verbose('finding sqs in store');
return JSON.parse(
readFileSync(join(this.storePath, 'sqs', instance + '.json'), {
encoding: 'utf-8',
}),
) as SqsRaw;
} catch (error) {
return {};
}
}
}

View File

@@ -0,0 +1,68 @@
import { readFileSync } from 'fs';
import { join } from 'path';
import { ConfigService } from '../../config/env.config';
import { Logger } from '../../config/logger.config';
import { IInsert, Repository } from '../abstract/abstract.repository';
import { ITypebotModel, TypebotRaw } from '../models';
export class TypebotRepository extends Repository {
constructor(private readonly typebotModel: ITypebotModel, private readonly configService: ConfigService) {
super(configService);
}
private readonly logger = new Logger('TypebotRepository');
public async create(data: TypebotRaw, instance: string): Promise<IInsert> {
try {
this.logger.verbose('creating typebot');
if (this.dbSettings.ENABLED) {
this.logger.verbose('saving typebot to db');
const insert = await this.typebotModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
this.logger.verbose('typebot saved to db: ' + insert.modifiedCount + ' typebot');
return { insertCount: insert.modifiedCount };
}
this.logger.verbose('saving typebot to store');
this.writeStore<TypebotRaw>({
path: join(this.storePath, 'typebot'),
fileName: instance,
data,
});
this.logger.verbose('typebot saved to store in path: ' + join(this.storePath, 'typebot') + '/' + instance);
this.logger.verbose('typebot created');
return { insertCount: 1 };
} catch (error) {
return error;
}
}
public async find(instance: string): Promise<TypebotRaw> {
try {
this.logger.verbose('finding typebot');
if (this.dbSettings.ENABLED) {
this.logger.verbose('finding typebot in db');
return await this.typebotModel.findOne({ _id: instance });
}
this.logger.verbose('finding typebot in store');
return JSON.parse(
readFileSync(join(this.storePath, 'typebot', instance + '.json'), {
encoding: 'utf-8',
}),
) as TypebotRaw;
} catch (error) {
return {
enabled: false,
url: '',
typebot: '',
expire: 0,
sessions: [],
};
}
}
}

View File

@@ -0,0 +1,62 @@
import { readFileSync } from 'fs';
import { join } from 'path';
import { ConfigService } from '../../config/env.config';
import { Logger } from '../../config/logger.config';
import { IInsert, Repository } from '../abstract/abstract.repository';
import { IWebsocketModel, WebsocketRaw } from '../models';
export class WebsocketRepository extends Repository {
constructor(private readonly websocketModel: IWebsocketModel, private readonly configService: ConfigService) {
super(configService);
}
private readonly logger = new Logger('WebsocketRepository');
public async create(data: WebsocketRaw, instance: string): Promise<IInsert> {
try {
this.logger.verbose('creating websocket');
if (this.dbSettings.ENABLED) {
this.logger.verbose('saving websocket to db');
const insert = await this.websocketModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
this.logger.verbose('websocket saved to db: ' + insert.modifiedCount + ' websocket');
return { insertCount: insert.modifiedCount };
}
this.logger.verbose('saving websocket to store');
this.writeStore<WebsocketRaw>({
path: join(this.storePath, 'websocket'),
fileName: instance,
data,
});
this.logger.verbose('websocket saved to store in path: ' + join(this.storePath, 'websocket') + '/' + instance);
this.logger.verbose('websocket created');
return { insertCount: 1 };
} catch (error) {
return error;
}
}
public async find(instance: string): Promise<WebsocketRaw> {
try {
this.logger.verbose('finding websocket');
if (this.dbSettings.ENABLED) {
this.logger.verbose('finding websocket in db');
return await this.websocketModel.findOne({ _id: instance });
}
this.logger.verbose('finding websocket in store');
return JSON.parse(
readFileSync(join(this.storePath, 'websocket', instance + '.json'), {
encoding: 'utf-8',
}),
) as WebsocketRaw;
} catch (error) {
return {};
}
}
}

View File

@@ -0,0 +1,52 @@
import { RequestHandler, Router } from 'express';
import { Logger } from '../../config/logger.config';
import { chamaaiSchema, instanceNameSchema } from '../../validate/validate.schema';
import { RouterBroker } from '../abstract/abstract.router';
import { ChamaaiDto } from '../dto/chamaai.dto';
import { InstanceDto } from '../dto/instance.dto';
import { chamaaiController } from '../whatsapp.module';
import { HttpStatus } from './index.router';
const logger = new Logger('ChamaaiRouter');
export class ChamaaiRouter extends RouterBroker {
constructor(...guards: RequestHandler[]) {
super();
this.router
.post(this.routerPath('set'), ...guards, async (req, res) => {
logger.verbose('request received in setChamaai');
logger.verbose('request body: ');
logger.verbose(req.body);
logger.verbose('request query: ');
logger.verbose(req.query);
const response = await this.dataValidate<ChamaaiDto>({
request: req,
schema: chamaaiSchema,
ClassRef: ChamaaiDto,
execute: (instance, data) => chamaaiController.createChamaai(instance, data),
});
res.status(HttpStatus.CREATED).json(response);
})
.get(this.routerPath('find'), ...guards, async (req, res) => {
logger.verbose('request received in findChamaai');
logger.verbose('request body: ');
logger.verbose(req.body);
logger.verbose('request query: ');
logger.verbose(req.query);
const response = await this.dataValidate<InstanceDto>({
request: req,
schema: instanceNameSchema,
ClassRef: InstanceDto,
execute: (instance) => chamaaiController.findChamaai(instance),
});
res.status(HttpStatus.OK).json(response);
});
}
public readonly router = Router();
}

View File

@@ -7,6 +7,7 @@ import {
deleteMessageSchema,
messageUpSchema,
messageValidateSchema,
presenceSchema,
privacySettingsSchema,
profileNameSchema,
profilePictureSchema,
@@ -26,6 +27,7 @@ import {
ProfilePictureDto,
ProfileStatusDto,
ReadMessageDto,
SendPresenceDto,
WhatsAppNumberDto,
} from '../dto/chat.dto';
import { InstanceDto } from '../dto/instance.dto';
@@ -228,6 +230,22 @@ export class ChatRouter extends RouterBroker {
return res.status(HttpStatus.OK).json(response);
})
.post(this.routerPath('sendPresence'), ...guards, async (req, res) => {
logger.verbose('request received in sendPresence');
logger.verbose('request body: ');
logger.verbose(req.body);
logger.verbose('request query: ');
logger.verbose(req.query);
const response = await this.dataValidate<null>({
request: req,
schema: presenceSchema,
ClassRef: SendPresenceDto,
execute: (instance, data) => chatController.sendPresence(instance, data),
});
return res.status(HttpStatus.CREATED).json(response);
})
// Profile routes
.get(this.routerPath('fetchPrivacySettings'), ...guards, async (req, res) => {
logger.verbose('request received in fetchPrivacySettings');

View File

@@ -4,14 +4,20 @@ import fs from 'fs';
import { Auth, configService } from '../../config/env.config';
import { authGuard } from '../guards/auth.guard';
import { instanceExistsGuard, instanceLoggedGuard } from '../guards/instance.guard';
import { ChamaaiRouter } from './chamaai.router';
import { ChatRouter } from './chat.router';
import { ChatwootRouter } from './chatwoot.router';
import { GroupRouter } from './group.router';
import { InstanceRouter } from './instance.router';
import { ProxyRouter } from './proxy.router';
import { RabbitmqRouter } from './rabbitmq.router';
import { MessageRouter } from './sendMessage.router';
import { SettingsRouter } from './settings.router';
import { SqsRouter } from './sqs.router';
import { TypebotRouter } from './typebot.router';
import { ViewsRouter } from './view.router';
import { WebhookRouter } from './webhook.router';
import { WebsocketRouter } from './websocket.router';
enum HttpStatus {
OK = 200,
@@ -25,24 +31,36 @@ enum HttpStatus {
const router = Router();
const authType = configService.get<Auth>('AUTHENTICATION').TYPE;
const serverConfig = configService.get('SERVER');
const guards = [instanceExistsGuard, instanceLoggedGuard, authGuard[authType]];
const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
if (!serverConfig.DISABLE_MANAGER) router.use('/manager', new ViewsRouter().router);
router
.get('/', (req, res) => {
res.status(HttpStatus.OK).json({
status: HttpStatus.OK,
message: 'Welcome to the Evolution API, it is working!',
version: packageJson.version,
swagger: !serverConfig.DISABLE_DOCS ? `${req.protocol}://${req.get('host')}/docs` : undefined,
manager: !serverConfig.DISABLE_MANAGER ? `${req.protocol}://${req.get('host')}/manager` : undefined,
documentation: `https://doc.evolution-api.com`,
});
})
.use('/instance', new InstanceRouter(configService, ...guards).router, new ViewsRouter(instanceExistsGuard).router)
.use('/instance', new InstanceRouter(configService, ...guards).router)
.use('/message', new MessageRouter(...guards).router)
.use('/chat', new ChatRouter(...guards).router)
.use('/group', new GroupRouter(...guards).router)
.use('/webhook', new WebhookRouter(...guards).router)
.use('/chatwoot', new ChatwootRouter(...guards).router)
.use('/settings', new SettingsRouter(...guards).router);
.use('/settings', new SettingsRouter(...guards).router)
.use('/websocket', new WebsocketRouter(...guards).router)
.use('/rabbitmq', new RabbitmqRouter(...guards).router)
.use('/sqs', new SqsRouter(...guards).router)
.use('/typebot', new TypebotRouter(...guards).router)
.use('/proxy', new ProxyRouter(...guards).router)
.use('/chamaai', new ChamaaiRouter(...guards).router);
export { HttpStatus, router };

View File

@@ -2,7 +2,7 @@ import { RequestHandler, Router } from 'express';
import { Auth, ConfigService, Database } from '../../config/env.config';
import { Logger } from '../../config/logger.config';
import { dbserver } from '../../db/db.connect';
import { dbserver } from '../../libs/db.connect';
import { instanceNameSchema, oldTokenSchema } from '../../validate/validate.schema';
import { RouterBroker } from '../abstract/abstract.router';
import { InstanceDto } from '../dto/instance.dto';
@@ -161,7 +161,9 @@ export class InstanceRouter extends RouterBroker {
if (db.ENABLED) {
try {
await dbserver.dropDatabase();
return res.status(HttpStatus.CREATED).json({ error: false, message: 'Database deleted' });
return res
.status(HttpStatus.CREATED)
.json({ status: 'SUCCESS', error: false, response: { message: 'database deleted' } });
} catch (error) {
return res.status(HttpStatus.INTERNAL_SERVER_ERROR).json({ error: true, message: error.message });
}

View File

@@ -0,0 +1,52 @@
import { RequestHandler, Router } from 'express';
import { Logger } from '../../config/logger.config';
import { instanceNameSchema, proxySchema } from '../../validate/validate.schema';
import { RouterBroker } from '../abstract/abstract.router';
import { InstanceDto } from '../dto/instance.dto';
import { ProxyDto } from '../dto/proxy.dto';
import { proxyController } from '../whatsapp.module';
import { HttpStatus } from './index.router';
const logger = new Logger('ProxyRouter');
export class ProxyRouter extends RouterBroker {
constructor(...guards: RequestHandler[]) {
super();
this.router
.post(this.routerPath('set'), ...guards, async (req, res) => {
logger.verbose('request received in setProxy');
logger.verbose('request body: ');
logger.verbose(req.body);
logger.verbose('request query: ');
logger.verbose(req.query);
const response = await this.dataValidate<ProxyDto>({
request: req,
schema: proxySchema,
ClassRef: ProxyDto,
execute: (instance, data) => proxyController.createProxy(instance, data),
});
res.status(HttpStatus.CREATED).json(response);
})
.get(this.routerPath('find'), ...guards, async (req, res) => {
logger.verbose('request received in findProxy');
logger.verbose('request body: ');
logger.verbose(req.body);
logger.verbose('request query: ');
logger.verbose(req.query);
const response = await this.dataValidate<InstanceDto>({
request: req,
schema: instanceNameSchema,
ClassRef: InstanceDto,
execute: (instance) => proxyController.findProxy(instance),
});
res.status(HttpStatus.OK).json(response);
});
}
public readonly router = Router();
}

View File

@@ -0,0 +1,52 @@
import { RequestHandler, Router } from 'express';
import { Logger } from '../../config/logger.config';
import { instanceNameSchema, rabbitmqSchema } from '../../validate/validate.schema';
import { RouterBroker } from '../abstract/abstract.router';
import { InstanceDto } from '../dto/instance.dto';
import { RabbitmqDto } from '../dto/rabbitmq.dto';
import { rabbitmqController } from '../whatsapp.module';
import { HttpStatus } from './index.router';
const logger = new Logger('RabbitmqRouter');
export class RabbitmqRouter extends RouterBroker {
constructor(...guards: RequestHandler[]) {
super();
this.router
.post(this.routerPath('set'), ...guards, async (req, res) => {
logger.verbose('request received in setRabbitmq');
logger.verbose('request body: ');
logger.verbose(req.body);
logger.verbose('request query: ');
logger.verbose(req.query);
const response = await this.dataValidate<RabbitmqDto>({
request: req,
schema: rabbitmqSchema,
ClassRef: RabbitmqDto,
execute: (instance, data) => rabbitmqController.createRabbitmq(instance, data),
});
res.status(HttpStatus.CREATED).json(response);
})
.get(this.routerPath('find'), ...guards, async (req, res) => {
logger.verbose('request received in findRabbitmq');
logger.verbose('request body: ');
logger.verbose(req.body);
logger.verbose('request query: ');
logger.verbose(req.query);
const response = await this.dataValidate<InstanceDto>({
request: req,
schema: instanceNameSchema,
ClassRef: InstanceDto,
execute: (instance) => rabbitmqController.findRabbitmq(instance),
});
res.status(HttpStatus.OK).json(response);
});
}
public readonly router = Router();
}

Some files were not shown because too many files have changed in this diff Show More