mirror of
https://github.com/EvolutionAPI/evolution-api.git
synced 2025-12-19 11:52:20 -06:00
Compare commits
117 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
530aec92a9 | ||
|
|
deb8f2a0b7 | ||
|
|
5c247e3d2c | ||
|
|
04b9a070c4 | ||
|
|
dd2caf720c | ||
|
|
0d16a7aab0 | ||
|
|
31325d0999 | ||
|
|
6f99784224 | ||
|
|
201e6f7e7b | ||
|
|
c4d41134b8 | ||
|
|
680c92ecec | ||
|
|
deb07d2b7f | ||
|
|
3a14fc373a | ||
|
|
c364d3fdca | ||
|
|
07ad5756eb | ||
|
|
da568e4ea5 | ||
|
|
ad819bf3ba | ||
|
|
b502ebd23a | ||
|
|
7c5d94c19e | ||
|
|
a16b5f4644 | ||
|
|
f3cb8c531b | ||
|
|
469e696ab7 | ||
|
|
d99ccd9df6 | ||
|
|
3b3118d764 | ||
|
|
84386847e2 | ||
|
|
0da3d100b3 | ||
|
|
56d621bab8 | ||
|
|
f1571b5f66 | ||
|
|
55f8e179af | ||
|
|
ab5289a136 | ||
|
|
e05c48979d | ||
|
|
24c880343b | ||
|
|
b3b4ee7a28 | ||
|
|
341148612f | ||
|
|
79864e97d6 | ||
|
|
ed5e66e430 | ||
|
|
074a861fb4 | ||
|
|
b88656829e | ||
|
|
aefe6a5943 | ||
|
|
3d743f8498 | ||
|
|
0186fff67d | ||
|
|
38f61cdf75 | ||
|
|
84366002db | ||
|
|
eff5bb74b5 | ||
|
|
2614088fae | ||
|
|
3699e04db9 | ||
|
|
0dca009c01 | ||
|
|
1b39eb1a23 | ||
|
|
2637aebb7f | ||
|
|
8afcfde078 | ||
|
|
9ea1eaf3ed | ||
|
|
66d06afaf7 | ||
|
|
cffcca9722 | ||
|
|
fe2b9774d8 | ||
|
|
3d02fabef4 | ||
|
|
f89c2b1f63 | ||
|
|
ee755d5a6c | ||
|
|
65e2ecf88e | ||
|
|
332ec69ee8 | ||
|
|
1ce30f8431 | ||
|
|
3ae6944307 | ||
|
|
52533d4b38 | ||
|
|
38409d9336 | ||
|
|
d344e513c4 | ||
|
|
9af7f67930 | ||
|
|
f95d938fb6 | ||
|
|
f74a7e87bd | ||
|
|
d3fce5fc89 | ||
|
|
14f3f3d2ac | ||
|
|
127d5b97c4 | ||
|
|
7ef1c097e8 | ||
|
|
80e3116cd8 | ||
|
|
46bac55bb3 | ||
|
|
2cadafd5c1 | ||
|
|
bb27dca21c | ||
|
|
86fc9fbffa | ||
|
|
9bdbfc6f4f | ||
|
|
28a7d9c62b | ||
|
|
2ca344b17c | ||
|
|
1bf2278f31 | ||
|
|
6188ab0d30 | ||
|
|
f016b53013 | ||
|
|
127cd3e843 | ||
|
|
457dbe5831 | ||
|
|
8d73fb1161 | ||
|
|
af5746bb39 | ||
|
|
3f27d018c7 | ||
|
|
68402393b5 | ||
|
|
2ad33857f4 | ||
|
|
d3c7677dc7 | ||
|
|
73e92f9ef5 | ||
|
|
fcc8748daf | ||
|
|
312ee249b6 | ||
|
|
e4548f6961 | ||
|
|
1b93aac8c5 | ||
|
|
e7ed666037 | ||
|
|
85ca0683ed | ||
|
|
78689a23e5 | ||
|
|
ba63a55883 | ||
|
|
dc3d59bae1 | ||
|
|
0a851b935e | ||
|
|
ddc75d710f | ||
|
|
5482601b41 | ||
|
|
249aecbc0d | ||
|
|
03f3020e9f | ||
|
|
e151eb85f0 | ||
|
|
348586553e | ||
|
|
fb6e58b3c4 | ||
|
|
67e98456bb | ||
|
|
3e47420534 | ||
|
|
1d3d557c43 | ||
|
|
3f41974a75 | ||
|
|
3e3c7397a5 | ||
|
|
dcb51702e7 | ||
|
|
de0c9a1eff | ||
|
|
dd0c1e20a7 | ||
|
|
4769d75dc3 |
14
.eslintrc.js
14
.eslintrc.js
@@ -3,10 +3,14 @@ module.exports = {
|
|||||||
parserOptions: {
|
parserOptions: {
|
||||||
sourceType: 'CommonJS',
|
sourceType: 'CommonJS',
|
||||||
},
|
},
|
||||||
plugins: ['@typescript-eslint/eslint-plugin'],
|
plugins: [
|
||||||
|
'@typescript-eslint',
|
||||||
|
'simple-import-sort',
|
||||||
|
'import'
|
||||||
|
],
|
||||||
extends: [
|
extends: [
|
||||||
|
'eslint:recommended',
|
||||||
'plugin:@typescript-eslint/recommended',
|
'plugin:@typescript-eslint/recommended',
|
||||||
'plugin:prettier/recommended',
|
|
||||||
'plugin:prettier/recommended'
|
'plugin:prettier/recommended'
|
||||||
],
|
],
|
||||||
globals: {
|
globals: {
|
||||||
@@ -26,7 +30,11 @@ module.exports = {
|
|||||||
'@typescript-eslint/no-explicit-any': 'off',
|
'@typescript-eslint/no-explicit-any': 'off',
|
||||||
'@typescript-eslint/no-empty-function': 'off',
|
'@typescript-eslint/no-empty-function': 'off',
|
||||||
'@typescript-eslint/no-non-null-assertion': 'off',
|
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||||
'@typescript-eslint/no-unused-vars': 'off',
|
'@typescript-eslint/no-unused-vars': 'error',
|
||||||
|
'import/first': 'error',
|
||||||
|
'import/no-duplicates': 'error',
|
||||||
|
'simple-import-sort/imports': 'error',
|
||||||
|
'simple-import-sort/exports': 'error',
|
||||||
'@typescript-eslint/ban-types': [
|
'@typescript-eslint/ban-types': [
|
||||||
'error',
|
'error',
|
||||||
{
|
{
|
||||||
|
|||||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -22,12 +22,13 @@ docker-compose.yaml
|
|||||||
/yarn.lock
|
/yarn.lock
|
||||||
/package-lock.json
|
/package-lock.json
|
||||||
|
|
||||||
# IDE - VSCode
|
# IDEs
|
||||||
.vscode/*
|
.vscode/*
|
||||||
!.vscode/settings.json
|
!.vscode/settings.json
|
||||||
!.vscode/tasks.json
|
!.vscode/tasks.json
|
||||||
!.vscode/launch.json
|
!.vscode/launch.json
|
||||||
!.vscode/extensions.json
|
!.vscode/extensions.json
|
||||||
|
.nova/*
|
||||||
|
|
||||||
# Prisma
|
# Prisma
|
||||||
/prisma/migrations
|
/prisma/migrations
|
||||||
@@ -40,3 +41,6 @@ docker-compose.yaml
|
|||||||
/store
|
/store
|
||||||
|
|
||||||
/temp/*
|
/temp/*
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
|
*.DS_Store
|
||||||
@@ -2,8 +2,11 @@ module.exports = {
|
|||||||
semi: true,
|
semi: true,
|
||||||
trailingComma: 'all',
|
trailingComma: 'all',
|
||||||
singleQuote: true,
|
singleQuote: true,
|
||||||
printWidth: 90,
|
printWidth: 120,
|
||||||
|
arrowParens: 'always',
|
||||||
tabWidth: 2,
|
tabWidth: 2,
|
||||||
bracketSameLine: true,
|
useTabs: false,
|
||||||
bracketSpacing: true
|
bracketSameLine: false,
|
||||||
|
bracketSpacing: true,
|
||||||
|
parser: 'typescript'
|
||||||
}
|
}
|
||||||
59
CHANGELOG.md
59
CHANGELOG.md
@@ -1,3 +1,62 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
|
* Fixed error return bug
|
||||||
|
* Fixed problem of getting message when deleting message in chatwoot
|
||||||
|
* Change in error return pattern
|
||||||
|
|
||||||
|
# 1.4.6 (2023-07-26 17:54)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* Fixed bug of creating new inbox by chatwoot
|
||||||
|
* When conversation reopens is pending when conversation pending is true
|
||||||
|
* Added docker-compose file with dockerhub image
|
||||||
|
|
||||||
|
# 1.4.5 (2023-07-26 09:32)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* Fixed problems in localization template in chatwoot
|
||||||
|
* Fix mids going duplicated in chatwoot
|
||||||
|
|
||||||
# 1.4.4 (2023-07-25 15:24)
|
# 1.4.4 (2023-07-25 15:24)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ CLEAN_STORE_CONTACTS=true
|
|||||||
CLEAN_STORE_CHATS=true
|
CLEAN_STORE_CHATS=true
|
||||||
|
|
||||||
# Permanent data storage
|
# 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_URI=mongodb://root:root@mongodb:27017/?authSource=admin&readPreference=primary&ssl=false&directConnection=true
|
||||||
DATABASE_CONNECTION_DB_PREFIX_NAME=evdocker
|
DATABASE_CONNECTION_DB_PREFIX_NAME=evdocker
|
||||||
|
|
||||||
@@ -42,10 +42,15 @@ DATABASE_SAVE_MESSAGE_UPDATE=false
|
|||||||
DATABASE_SAVE_DATA_CONTACTS=false
|
DATABASE_SAVE_DATA_CONTACTS=false
|
||||||
DATABASE_SAVE_DATA_CHATS=false
|
DATABASE_SAVE_DATA_CHATS=false
|
||||||
|
|
||||||
REDIS_ENABLED=true
|
REDIS_ENABLED=false
|
||||||
REDIS_URI=redis://redis:6379
|
REDIS_URI=redis://redis:6379
|
||||||
REDIS_PREFIX_KEY=evdocker
|
REDIS_PREFIX_KEY=evdocker
|
||||||
|
|
||||||
|
RABBITMQ_ENABLED=false
|
||||||
|
RABBITMQ_URI=amqp://guest:guest@rabbitmq:5672
|
||||||
|
|
||||||
|
WEBSOCKET_ENABLED=false
|
||||||
|
|
||||||
# Global Webhook Settings
|
# Global Webhook Settings
|
||||||
# Each instance's Webhook URL and events will be requested at the time it is created
|
# 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
|
## Define a global webhook that will listen for enabled events from all instances
|
||||||
@@ -84,6 +89,7 @@ CONFIG_SESSION_PHONE_NAME=chrome
|
|||||||
|
|
||||||
# Set qrcode display limit
|
# Set qrcode display limit
|
||||||
QRCODE_LIMIT=30
|
QRCODE_LIMIT=30
|
||||||
|
QRCODE_COLOR=#198754
|
||||||
|
|
||||||
# Defines an authentication type for the api
|
# Defines an authentication type for the api
|
||||||
# We recommend using the apikey because it will allow you to use a custom token,
|
# We recommend using the apikey because it will allow you to use a custom token,
|
||||||
|
|||||||
13
Dockerfile
13
Dockerfile
@@ -1,16 +1,17 @@
|
|||||||
FROM node:16.18-alpine
|
FROM node:16.18-alpine
|
||||||
|
|
||||||
LABEL version="1.1.3" description="Api to control whatsapp features through http requests."
|
LABEL version="1.5.0" description="Api to control whatsapp features through http requests."
|
||||||
LABEL maintainer="Davidson Gomes" git="https://github.com/DavidsonGomes"
|
LABEL maintainer="Davidson Gomes" git="https://github.com/DavidsonGomes"
|
||||||
LABEL contact="contato@agenciadgcode.com"
|
LABEL contact="contato@agenciadgcode.com"
|
||||||
|
|
||||||
RUN apk update && apk upgrade && \
|
RUN apk update && apk upgrade && \
|
||||||
apk add --no-cache git
|
apk add --no-cache git tzdata ffmpeg wget curl
|
||||||
|
|
||||||
WORKDIR /evolution
|
WORKDIR /evolution
|
||||||
|
|
||||||
COPY ./package.json .
|
COPY ./package.json .
|
||||||
|
|
||||||
|
ENV TZ=America/Sao_Paulo
|
||||||
ENV DOCKER_ENV=true
|
ENV DOCKER_ENV=true
|
||||||
|
|
||||||
ENV SERVER_URL=http://localhost:8080
|
ENV SERVER_URL=http://localhost:8080
|
||||||
@@ -50,7 +51,12 @@ ENV REDIS_ENABLED=false
|
|||||||
ENV REDIS_URI=redis://redis:6379
|
ENV REDIS_URI=redis://redis:6379
|
||||||
ENV REDIS_PREFIX_KEY=evolution
|
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 WEBHOOK_GLOBAL_URL=
|
||||||
ENV WEBHOOK_GLOBAL_ENABLED=false
|
ENV WEBHOOK_GLOBAL_ENABLED=false
|
||||||
|
|
||||||
ENV WEBHOOK_GLOBAL_WEBHOOK_BY_EVENTS=false
|
ENV WEBHOOK_GLOBAL_WEBHOOK_BY_EVENTS=false
|
||||||
@@ -82,6 +88,7 @@ ENV CONFIG_SESSION_PHONE_CLIENT=EvolutionAPI
|
|||||||
ENV CONFIG_SESSION_PHONE_NAME=chrome
|
ENV CONFIG_SESSION_PHONE_NAME=chrome
|
||||||
|
|
||||||
ENV QRCODE_LIMIT=30
|
ENV QRCODE_LIMIT=30
|
||||||
|
ENV QRCODE_COLOR=#198754
|
||||||
|
|
||||||
ENV AUTHENTICATION_TYPE=apikey
|
ENV AUTHENTICATION_TYPE=apikey
|
||||||
|
|
||||||
|
|||||||
1
Extras/appsmith/manager.json
Normal file
1
Extras/appsmith/manager.json
Normal file
File diff suppressed because one or more lines are too long
241
Extras/chatwoot/configurar_admin.json
Normal file
241
Extras/chatwoot/configurar_admin.json
Normal 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": []
|
||||||
|
}
|
||||||
456
Extras/chatwoot/criador_de_empresas.json
Normal file
456
Extras/chatwoot/criador_de_empresas.json
Normal 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": []
|
||||||
|
}
|
||||||
510
Extras/chatwoot/criador_de_inbox.json
Normal file
510
Extras/chatwoot/criador_de_inbox.json
Normal 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": []
|
||||||
|
}
|
||||||
1
Extras/typebot/typebot-example.json
Normal file
1
Extras/typebot/typebot-example.json
Normal file
File diff suppressed because one or more lines are too long
13
README.md
13
README.md
@@ -7,7 +7,8 @@
|
|||||||
[](https://evolution-api.com/postman)
|
[](https://evolution-api.com/postman)
|
||||||
[](https://doc.evolution-api.com)
|
[](https://doc.evolution-api.com)
|
||||||
[](./LICENSE)
|
[](./LICENSE)
|
||||||
[](https://app.picpay.com/user/davidsongomes1998)
|
[](https://app.picpay.com/user/davidsongomes1998)
|
||||||
|
[](https://bmc.link/evolutionapi)
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -34,7 +35,15 @@ This code was produced based on the baileys library and it is still under develo
|
|||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<a href="https://app.picpay.com/user/davidsongomes1998" target="_blank" rel="noopener noreferrer">
|
<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
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<a href="https://bmc.link/evolutionapi" target="_blank" rel="noopener noreferrer">
|
||||||
|
<img src="./public/images/bmc_qr.png" style="width: 50% !important;">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
28
docker-compose.yaml.example.dockerhub
Normal file
28
docker-compose.yaml.example.dockerhub
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
version: '3.3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
api:
|
||||||
|
container_name: evolution_api
|
||||||
|
image: davidsongomes/evolution-api:latest
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- 8080:8080
|
||||||
|
volumes:
|
||||||
|
- evolution_instances:/evolution/instances
|
||||||
|
- evolution_store:/evolution/store
|
||||||
|
networks:
|
||||||
|
- evolution-net
|
||||||
|
env_file:
|
||||||
|
- ./Docker/.env
|
||||||
|
command: ['node', './dist/src/main.js']
|
||||||
|
expose:
|
||||||
|
- 8080
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
evolution_instances:
|
||||||
|
evolution_store:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
evolution-net:
|
||||||
|
external: true
|
||||||
|
|
||||||
23
package.json
23
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "evolution-api",
|
"name": "evolution-api",
|
||||||
"version": "1.4.4",
|
"version": "1.5.0",
|
||||||
"description": "Rest api for communication with WhatsApp",
|
"description": "Rest api for communication with WhatsApp",
|
||||||
"main": "./dist/src/main.js",
|
"main": "./dist/src/main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -8,7 +8,8 @@
|
|||||||
"start": "ts-node --files --transpile-only ./src/main.ts",
|
"start": "ts-node --files --transpile-only ./src/main.ts",
|
||||||
"start:prod": "bash start.sh",
|
"start:prod": "bash start.sh",
|
||||||
"dev:server": "clear && tsnd --files --transpile-only --respawn --ignore-watch node_modules ./src/main.ts",
|
"dev:server": "clear && tsnd --files --transpile-only --respawn --ignore-watch node_modules ./src/main.ts",
|
||||||
"test": "clear && tsnd --files --transpile-only --respawn --ignore-watch node_modules ./test/all.test.ts"
|
"test": "clear && tsnd --files --transpile-only --respawn --ignore-watch node_modules ./test/all.test.ts",
|
||||||
|
"lint": "eslint --fix --ext .ts src"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -45,7 +46,8 @@
|
|||||||
"@figuro/chatwoot-sdk": "^1.1.14",
|
"@figuro/chatwoot-sdk": "^1.1.14",
|
||||||
"@hapi/boom": "^10.0.1",
|
"@hapi/boom": "^10.0.1",
|
||||||
"@sentry/node": "^7.59.2",
|
"@sentry/node": "^7.59.2",
|
||||||
"@whiskeysockets/baileys": "^6.4.0",
|
"@whiskeysockets/baileys": "github:EvolutionAPI/Baileys",
|
||||||
|
"amqplib": "^0.10.3",
|
||||||
"axios": "^1.3.5",
|
"axios": "^1.3.5",
|
||||||
"class-validator": "^0.13.2",
|
"class-validator": "^0.13.2",
|
||||||
"compression": "^1.7.4",
|
"compression": "^1.7.4",
|
||||||
@@ -62,16 +64,18 @@
|
|||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"jsonschema": "^1.4.1",
|
"jsonschema": "^1.4.1",
|
||||||
"jsonwebtoken": "^8.5.1",
|
"jsonwebtoken": "^8.5.1",
|
||||||
|
"libphonenumber-js": "^1.10.39",
|
||||||
"link-preview-js": "^3.0.4",
|
"link-preview-js": "^3.0.4",
|
||||||
"mongoose": "^6.10.5",
|
"mongoose": "^6.10.5",
|
||||||
"node-cache": "^5.1.2",
|
"node-cache": "^5.1.2",
|
||||||
"node-mime-types": "^1.1.0",
|
"node-mime-types": "^1.1.0",
|
||||||
"pino": "^8.11.0",
|
"pino": "^8.11.0",
|
||||||
"proxy-agent": "^6.2.1",
|
"proxy-agent": "^6.3.0",
|
||||||
"qrcode": "^1.5.1",
|
"qrcode": "^1.5.1",
|
||||||
"qrcode-terminal": "^0.12.0",
|
"qrcode-terminal": "^0.12.0",
|
||||||
"redis": "^4.6.5",
|
"redis": "^4.6.5",
|
||||||
"sharp": "^0.30.7",
|
"sharp": "^0.30.7",
|
||||||
|
"socket.io": "^4.7.1",
|
||||||
"uuid": "^9.0.0"
|
"uuid": "^9.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -80,16 +84,19 @@
|
|||||||
"@types/express": "^4.17.17",
|
"@types/express": "^4.17.17",
|
||||||
"@types/js-yaml": "^4.0.5",
|
"@types/js-yaml": "^4.0.5",
|
||||||
"@types/jsonwebtoken": "^8.5.9",
|
"@types/jsonwebtoken": "^8.5.9",
|
||||||
|
"@types/mime-types": "^2.1.1",
|
||||||
"@types/node": "^18.15.11",
|
"@types/node": "^18.15.11",
|
||||||
"@types/qrcode": "^1.5.0",
|
"@types/qrcode": "^1.5.0",
|
||||||
"@types/qrcode-terminal": "^0.12.0",
|
"@types/qrcode-terminal": "^0.12.0",
|
||||||
"@types/uuid": "^8.3.4",
|
"@types/uuid": "^8.3.4",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.57.1",
|
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
||||||
"@typescript-eslint/parser": "^5.57.1",
|
"@typescript-eslint/parser": "^5.62.0",
|
||||||
"eslint": "^8.38.0",
|
"eslint": "^8.45.0",
|
||||||
"eslint-config-prettier": "^8.8.0",
|
"eslint-config-prettier": "^8.8.0",
|
||||||
|
"eslint-plugin-import": "^2.27.5",
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
"prettier": "^2.8.7",
|
"eslint-plugin-simple-import-sort": "^10.0.0",
|
||||||
|
"prettier": "^2.8.8",
|
||||||
"ts-node-dev": "^2.0.0",
|
"ts-node-dev": "^2.0.0",
|
||||||
"typescript": "^4.9.5"
|
"typescript": "^4.9.5"
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
public/images/bmc_qr.png
Normal file
BIN
public/images/bmc_qr.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
BIN
public/images/picpay-qr.jpeg
Normal file
BIN
public/images/picpay-qr.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 111 KiB |
@@ -1,7 +1,7 @@
|
|||||||
|
import { isBooleanString } from 'class-validator';
|
||||||
import { readFileSync } from 'fs';
|
import { readFileSync } from 'fs';
|
||||||
import { load } from 'js-yaml';
|
import { load } from 'js-yaml';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { isBooleanString } from 'class-validator';
|
|
||||||
|
|
||||||
export type HttpServer = { TYPE: 'http' | 'https'; PORT: number; URL: string };
|
export type HttpServer = { TYPE: 'http' | 'https'; PORT: number; URL: string };
|
||||||
|
|
||||||
@@ -14,15 +14,7 @@ export type Cors = {
|
|||||||
|
|
||||||
export type LogBaileys = 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace';
|
export type LogBaileys = 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace';
|
||||||
|
|
||||||
export type LogLevel =
|
export type LogLevel = 'ERROR' | 'WARN' | 'DEBUG' | 'INFO' | 'LOG' | 'VERBOSE' | 'DARK' | 'WEBHOOKS';
|
||||||
| 'ERROR'
|
|
||||||
| 'WARN'
|
|
||||||
| 'DEBUG'
|
|
||||||
| 'INFO'
|
|
||||||
| 'LOG'
|
|
||||||
| 'VERBOSE'
|
|
||||||
| 'DARK'
|
|
||||||
| 'WEBHOOKS';
|
|
||||||
|
|
||||||
export type Log = {
|
export type Log = {
|
||||||
LEVEL: LogLevel[];
|
LEVEL: LogLevel[];
|
||||||
@@ -69,6 +61,15 @@ export type Redis = {
|
|||||||
PREFIX_KEY: string;
|
PREFIX_KEY: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type Rabbitmq = {
|
||||||
|
ENABLED: boolean;
|
||||||
|
URI: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Websocket = {
|
||||||
|
ENABLED: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export type EventsWebhook = {
|
export type EventsWebhook = {
|
||||||
APPLICATION_STARTUP: boolean;
|
APPLICATION_STARTUP: boolean;
|
||||||
QRCODE_UPDATED: boolean;
|
QRCODE_UPDATED: boolean;
|
||||||
@@ -113,7 +114,7 @@ export type GlobalWebhook = {
|
|||||||
export type SslConf = { PRIVKEY: string; FULLCHAIN: string };
|
export type SslConf = { PRIVKEY: string; FULLCHAIN: string };
|
||||||
export type Webhook = { GLOBAL?: GlobalWebhook; EVENTS: EventsWebhook };
|
export type Webhook = { GLOBAL?: GlobalWebhook; EVENTS: EventsWebhook };
|
||||||
export type ConfigSessionPhone = { CLIENT: string; NAME: string };
|
export type ConfigSessionPhone = { CLIENT: string; NAME: string };
|
||||||
export type QrCode = { LIMIT: number };
|
export type QrCode = { LIMIT: number; COLOR: string };
|
||||||
export type Production = boolean;
|
export type Production = boolean;
|
||||||
|
|
||||||
export interface Env {
|
export interface Env {
|
||||||
@@ -124,6 +125,8 @@ export interface Env {
|
|||||||
CLEAN_STORE: CleanStoreConf;
|
CLEAN_STORE: CleanStoreConf;
|
||||||
DATABASE: Database;
|
DATABASE: Database;
|
||||||
REDIS: Redis;
|
REDIS: Redis;
|
||||||
|
RABBITMQ: Rabbitmq;
|
||||||
|
WEBSOCKET: Websocket;
|
||||||
LOG: Log;
|
LOG: Log;
|
||||||
DEL_INSTANCE: DelInstance;
|
DEL_INSTANCE: DelInstance;
|
||||||
WEBHOOK: Webhook;
|
WEBHOOK: Webhook;
|
||||||
@@ -156,9 +159,7 @@ export class ConfigService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private envYaml(): Env {
|
private envYaml(): Env {
|
||||||
return load(
|
return load(readFileSync(join(process.cwd(), 'src', 'env.yml'), { encoding: 'utf-8' })) as Env;
|
||||||
readFileSync(join(process.cwd(), 'src', 'env.yml'), { encoding: 'utf-8' }),
|
|
||||||
) as Env;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private envProcess(): Env {
|
private envProcess(): Env {
|
||||||
@@ -211,6 +212,13 @@ export class ConfigService {
|
|||||||
URI: process.env.REDIS_URI,
|
URI: process.env.REDIS_URI,
|
||||||
PREFIX_KEY: process.env.REDIS_PREFIX_KEY,
|
PREFIX_KEY: process.env.REDIS_PREFIX_KEY,
|
||||||
},
|
},
|
||||||
|
RABBITMQ: {
|
||||||
|
ENABLED: process.env?.RABBITMQ_ENABLED === 'true',
|
||||||
|
URI: process.env.RABBITMQ_URI,
|
||||||
|
},
|
||||||
|
WEBSOCKET: {
|
||||||
|
ENABLED: process.env?.WEBSOCKET_ENABLED === 'true',
|
||||||
|
},
|
||||||
LOG: {
|
LOG: {
|
||||||
LEVEL: process.env?.LOG_LEVEL.split(',') as LogLevel[],
|
LEVEL: process.env?.LOG_LEVEL.split(',') as LogLevel[],
|
||||||
COLOR: process.env?.LOG_COLOR === 'true',
|
COLOR: process.env?.LOG_COLOR === 'true',
|
||||||
@@ -244,8 +252,7 @@ export class ConfigService {
|
|||||||
CONNECTION_UPDATE: process.env?.WEBHOOK_EVENTS_CONNECTION_UPDATE === 'true',
|
CONNECTION_UPDATE: process.env?.WEBHOOK_EVENTS_CONNECTION_UPDATE === 'true',
|
||||||
GROUPS_UPSERT: process.env?.WEBHOOK_EVENTS_GROUPS_UPSERT === 'true',
|
GROUPS_UPSERT: process.env?.WEBHOOK_EVENTS_GROUPS_UPSERT === 'true',
|
||||||
GROUP_UPDATE: process.env?.WEBHOOK_EVENTS_GROUPS_UPDATE === 'true',
|
GROUP_UPDATE: process.env?.WEBHOOK_EVENTS_GROUPS_UPDATE === 'true',
|
||||||
GROUP_PARTICIPANTS_UPDATE:
|
GROUP_PARTICIPANTS_UPDATE: process.env?.WEBHOOK_EVENTS_GROUP_PARTICIPANTS_UPDATE === 'true',
|
||||||
process.env?.WEBHOOK_EVENTS_GROUP_PARTICIPANTS_UPDATE === 'true',
|
|
||||||
CALL: process.env?.WEBHOOK_EVENTS_CALL === 'true',
|
CALL: process.env?.WEBHOOK_EVENTS_CALL === 'true',
|
||||||
NEW_JWT_TOKEN: process.env?.WEBHOOK_EVENTS_NEW_JWT_TOKEN === 'true',
|
NEW_JWT_TOKEN: process.env?.WEBHOOK_EVENTS_NEW_JWT_TOKEN === 'true',
|
||||||
},
|
},
|
||||||
@@ -256,14 +263,14 @@ export class ConfigService {
|
|||||||
},
|
},
|
||||||
QRCODE: {
|
QRCODE: {
|
||||||
LIMIT: Number.parseInt(process.env.QRCODE_LIMIT) || 30,
|
LIMIT: Number.parseInt(process.env.QRCODE_LIMIT) || 30,
|
||||||
|
COLOR: process.env.QRCODE_COLOR || '#198754',
|
||||||
},
|
},
|
||||||
AUTHENTICATION: {
|
AUTHENTICATION: {
|
||||||
TYPE: process.env.AUTHENTICATION_TYPE as 'jwt',
|
TYPE: process.env.AUTHENTICATION_TYPE as 'jwt',
|
||||||
API_KEY: {
|
API_KEY: {
|
||||||
KEY: process.env.AUTHENTICATION_API_KEY,
|
KEY: process.env.AUTHENTICATION_API_KEY,
|
||||||
},
|
},
|
||||||
EXPOSE_IN_FETCH_INSTANCES:
|
EXPOSE_IN_FETCH_INSTANCES: process.env?.AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES === 'true',
|
||||||
process.env?.AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES === 'true',
|
|
||||||
JWT: {
|
JWT: {
|
||||||
EXPIRIN_IN: Number.isInteger(process.env?.AUTHENTICATION_JWT_EXPIRIN_IN)
|
EXPIRIN_IN: Number.isInteger(process.env?.AUTHENTICATION_JWT_EXPIRIN_IN)
|
||||||
? Number.parseInt(process.env.AUTHENTICATION_JWT_EXPIRIN_IN)
|
? Number.parseInt(process.env.AUTHENTICATION_JWT_EXPIRIN_IN)
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
import { configService, Log } from './env.config';
|
|
||||||
import dayjs from 'dayjs';
|
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) =>
|
const formatDateLog = (timestamp: number) =>
|
||||||
dayjs(timestamp)
|
dayjs(timestamp)
|
||||||
@@ -73,6 +76,8 @@ export class Logger {
|
|||||||
/*Command.UNDERSCORE +*/ Command.BRIGHT + Level[type],
|
/*Command.UNDERSCORE +*/ Command.BRIGHT + Level[type],
|
||||||
'[Evolution API]',
|
'[Evolution API]',
|
||||||
Command.BRIGHT + Color[type],
|
Command.BRIGHT + Color[type],
|
||||||
|
`v${packageJson.version}`,
|
||||||
|
Command.BRIGHT + Color[type],
|
||||||
process.pid.toString(),
|
process.pid.toString(),
|
||||||
Command.RESET,
|
Command.RESET,
|
||||||
Command.BRIGHT + Color[type],
|
Command.BRIGHT + Color[type],
|
||||||
|
|||||||
@@ -79,6 +79,13 @@ REDIS:
|
|||||||
URI: "redis://localhost:6379"
|
URI: "redis://localhost:6379"
|
||||||
PREFIX_KEY: "evolution"
|
PREFIX_KEY: "evolution"
|
||||||
|
|
||||||
|
RABBITMQ:
|
||||||
|
ENABLED: false
|
||||||
|
URI: "amqp://guest:guest@localhost:5672"
|
||||||
|
|
||||||
|
WEBSOCKET:
|
||||||
|
ENABLED: false
|
||||||
|
|
||||||
# Global Webhook Settings
|
# Global Webhook Settings
|
||||||
# Each instance's Webhook URL and events will be requested at the time it is created
|
# Each instance's Webhook URL and events will be requested at the time it is created
|
||||||
WEBHOOK:
|
WEBHOOK:
|
||||||
@@ -122,6 +129,7 @@ CONFIG_SESSION_PHONE:
|
|||||||
# Set qrcode display limit
|
# Set qrcode display limit
|
||||||
QRCODE:
|
QRCODE:
|
||||||
LIMIT: 30
|
LIMIT: 30
|
||||||
|
COLOR: '#198754'
|
||||||
|
|
||||||
# Defines an authentication type for the api
|
# Defines an authentication type for the api
|
||||||
# We recommend using the apikey because it will allow you to use a custom token,
|
# We recommend using the apikey because it will allow you to use a custom token,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ export class UnauthorizedException {
|
|||||||
throw {
|
throw {
|
||||||
status: HttpStatus.UNAUTHORIZED,
|
status: HttpStatus.UNAUTHORIZED,
|
||||||
error: 'Unauthorized',
|
error: 'Unauthorized',
|
||||||
message: objectError.length > 0 ? objectError : undefined,
|
message: objectError.length > 0 ? objectError : 'Unauthorized',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
43
src/libs/amqp.server.ts
Normal file
43
src/libs/amqp.server.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
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;
|
||||||
|
};
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import mongoose from 'mongoose';
|
import mongoose from 'mongoose';
|
||||||
|
|
||||||
import { configService, Database } from '../config/env.config';
|
import { configService, Database } from '../config/env.config';
|
||||||
import { Logger } from '../config/logger.config';
|
import { Logger } from '../config/logger.config';
|
||||||
|
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
import { createClient, RedisClientType } from '@redis/client';
|
import { createClient, RedisClientType } from '@redis/client';
|
||||||
import { Logger } from '../config/logger.config';
|
|
||||||
import { BufferJSON } from '@whiskeysockets/baileys';
|
import { BufferJSON } from '@whiskeysockets/baileys';
|
||||||
|
|
||||||
import { Redis } from '../config/env.config';
|
import { Redis } from '../config/env.config';
|
||||||
|
import { Logger } from '../config/logger.config';
|
||||||
|
|
||||||
export class RedisCache {
|
export class RedisCache {
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -59,11 +60,7 @@ export class RedisCache {
|
|||||||
this.logger.verbose('writeData: ' + field);
|
this.logger.verbose('writeData: ' + field);
|
||||||
const json = JSON.stringify(data, BufferJSON.replacer);
|
const json = JSON.stringify(data, BufferJSON.replacer);
|
||||||
|
|
||||||
return await this.client.hSet(
|
return await this.client.hSet(this.redisEnv.PREFIX_KEY + ':' + this.instanceName, field, json);
|
||||||
this.redisEnv.PREFIX_KEY + ':' + this.instanceName,
|
|
||||||
field,
|
|
||||||
json,
|
|
||||||
);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.error(error);
|
this.logger.error(error);
|
||||||
}
|
}
|
||||||
@@ -72,10 +69,7 @@ export class RedisCache {
|
|||||||
public async readData(field: string) {
|
public async readData(field: string) {
|
||||||
try {
|
try {
|
||||||
this.logger.verbose('readData: ' + field);
|
this.logger.verbose('readData: ' + field);
|
||||||
const data = await this.client.hGet(
|
const data = await this.client.hGet(this.redisEnv.PREFIX_KEY + ':' + this.instanceName, field);
|
||||||
this.redisEnv.PREFIX_KEY + ':' + this.instanceName,
|
|
||||||
field,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
this.logger.verbose('readData: ' + field + ' success');
|
this.logger.verbose('readData: ' + field + ' success');
|
||||||
@@ -92,10 +86,7 @@ export class RedisCache {
|
|||||||
public async removeData(field: string) {
|
public async removeData(field: string) {
|
||||||
try {
|
try {
|
||||||
this.logger.verbose('removeData: ' + field);
|
this.logger.verbose('removeData: ' + field);
|
||||||
return await this.client.hDel(
|
return await this.client.hDel(this.redisEnv.PREFIX_KEY + ':' + this.instanceName, field);
|
||||||
this.redisEnv.PREFIX_KEY + ':' + this.instanceName,
|
|
||||||
field,
|
|
||||||
);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.error(error);
|
this.logger.error(error);
|
||||||
}
|
}
|
||||||
@@ -104,9 +95,7 @@ export class RedisCache {
|
|||||||
public async delAll(hash?: string) {
|
public async delAll(hash?: string) {
|
||||||
try {
|
try {
|
||||||
this.logger.verbose('instance delAll: ' + hash);
|
this.logger.verbose('instance delAll: ' + hash);
|
||||||
const result = await this.client.del(
|
const result = await this.client.del(hash || this.redisEnv.PREFIX_KEY + ':' + this.instanceName);
|
||||||
hash || this.redisEnv.PREFIX_KEY + ':' + this.instanceName,
|
|
||||||
);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
44
src/libs/socket.server.ts
Normal file
44
src/libs/socket.server.ts
Normal 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;
|
||||||
|
};
|
||||||
67
src/main.ts
67
src/main.ts
@@ -1,16 +1,19 @@
|
|||||||
|
import 'express-async-errors';
|
||||||
|
|
||||||
import compression from 'compression';
|
import compression from 'compression';
|
||||||
import { configService, Cors, HttpServer } from './config/env.config';
|
|
||||||
import cors from 'cors';
|
import cors from 'cors';
|
||||||
import express, { json, NextFunction, Request, Response, urlencoded } from 'express';
|
import express, { json, NextFunction, Request, Response, urlencoded } from 'express';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
|
||||||
|
import { configService, Cors, HttpServer, Rabbitmq } from './config/env.config';
|
||||||
import { onUnexpectedError } from './config/error.config';
|
import { onUnexpectedError } from './config/error.config';
|
||||||
import { Logger } from './config/logger.config';
|
import { Logger } from './config/logger.config';
|
||||||
import { ROOT_DIR } from './config/path.config';
|
import { ROOT_DIR } from './config/path.config';
|
||||||
import { waMonitor } from './whatsapp/whatsapp.module';
|
import { initAMQP } from './libs/amqp.server';
|
||||||
import { HttpStatus, router } from './whatsapp/routers/index.router';
|
import { initIO } from './libs/socket.server';
|
||||||
import 'express-async-errors';
|
|
||||||
import { ServerUP } from './utils/server-up';
|
import { ServerUP } from './utils/server-up';
|
||||||
import * as Sentry from '@sentry/node';
|
import { HttpStatus, router } from './whatsapp/routers/index.router';
|
||||||
|
import { waMonitor } from './whatsapp/whatsapp.module';
|
||||||
|
|
||||||
function initWA() {
|
function initWA() {
|
||||||
waMonitor.loadInstance();
|
waMonitor.loadInstance();
|
||||||
@@ -20,32 +23,13 @@ function bootstrap() {
|
|||||||
const logger = new Logger('SERVER');
|
const logger = new Logger('SERVER');
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
// Sentry.init({
|
|
||||||
// dsn: '',
|
|
||||||
// integrations: [
|
|
||||||
// // enable HTTP calls tracing
|
|
||||||
// new Sentry.Integrations.Http({ tracing: true }),
|
|
||||||
// // enable Express.js middleware tracing
|
|
||||||
// new Sentry.Integrations.Express({ app }),
|
|
||||||
// // Automatically instrument Node.js libraries and frameworks
|
|
||||||
// ...Sentry.autoDiscoverNodePerformanceMonitoringIntegrations(),
|
|
||||||
// ],
|
|
||||||
|
|
||||||
// // Set tracesSampleRate to 1.0 to capture 100%
|
|
||||||
// // of transactions for performance monitoring.
|
|
||||||
// // We recommend adjusting this value in production
|
|
||||||
// tracesSampleRate: 1.0,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// app.use(Sentry.Handlers.requestHandler());
|
|
||||||
|
|
||||||
// app.use(Sentry.Handlers.tracingHandler());
|
|
||||||
|
|
||||||
app.use(
|
app.use(
|
||||||
cors({
|
cors({
|
||||||
origin(requestOrigin, callback) {
|
origin(requestOrigin, callback) {
|
||||||
const { ORIGIN } = configService.get<Cors>('CORS');
|
const { ORIGIN } = configService.get<Cors>('CORS');
|
||||||
!requestOrigin ? (requestOrigin = '*') : undefined;
|
if (ORIGIN.includes('*')) {
|
||||||
|
return callback(null, true);
|
||||||
|
}
|
||||||
if (ORIGIN.indexOf(requestOrigin) !== -1) {
|
if (ORIGIN.indexOf(requestOrigin) !== -1) {
|
||||||
return callback(null, true);
|
return callback(null, true);
|
||||||
}
|
}
|
||||||
@@ -65,26 +49,29 @@ function bootstrap() {
|
|||||||
|
|
||||||
app.use('/', router);
|
app.use('/', router);
|
||||||
|
|
||||||
// app.use(Sentry.Handlers.errorHandler());
|
|
||||||
|
|
||||||
// app.use(function onError(err, req, res, next) {
|
|
||||||
// res.statusCode = 500;
|
|
||||||
// res.end(res.sentry + '\n');
|
|
||||||
// });
|
|
||||||
|
|
||||||
app.use(
|
app.use(
|
||||||
(err: Error, req: Request, res: Response, next: NextFunction) => {
|
(err: Error, req: Request, res: Response, next: NextFunction) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return res.status(err['status'] || 500).json(err);
|
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) => {
|
(req: Request, res: Response, next: NextFunction) => {
|
||||||
const { method, url } = req;
|
const { method, url } = req;
|
||||||
|
|
||||||
res.status(HttpStatus.NOT_FOUND).json({
|
res.status(HttpStatus.NOT_FOUND).json({
|
||||||
status: HttpStatus.NOT_FOUND,
|
status: HttpStatus.NOT_FOUND,
|
||||||
message: `Cannot ${method.toUpperCase()} ${url}`,
|
|
||||||
error: 'Not Found',
|
error: 'Not Found',
|
||||||
|
response: {
|
||||||
|
message: [`Cannot ${method.toUpperCase()} ${url}`],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
next();
|
next();
|
||||||
@@ -96,12 +83,14 @@ function bootstrap() {
|
|||||||
ServerUP.app = app;
|
ServerUP.app = app;
|
||||||
const server = ServerUP[httpServer.TYPE];
|
const server = ServerUP[httpServer.TYPE];
|
||||||
|
|
||||||
server.listen(httpServer.PORT, () =>
|
server.listen(httpServer.PORT, () => logger.log(httpServer.TYPE.toUpperCase() + ' - ON: ' + httpServer.PORT));
|
||||||
logger.log(httpServer.TYPE.toUpperCase() + ' - ON: ' + httpServer.PORT),
|
|
||||||
);
|
|
||||||
|
|
||||||
initWA();
|
initWA();
|
||||||
|
|
||||||
|
initIO(server);
|
||||||
|
|
||||||
|
if (configService.get<Rabbitmq>('RABBITMQ').ENABLED) initAMQP();
|
||||||
|
|
||||||
onUnexpectedError();
|
onUnexpectedError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { Express } from 'express';
|
import { Express } from 'express';
|
||||||
import { readFileSync } from 'fs';
|
import { readFileSync } from 'fs';
|
||||||
import { configService, SslConf } from '../config/env.config';
|
|
||||||
import * as https from 'https';
|
|
||||||
import * as http from 'http';
|
import * as http from 'http';
|
||||||
|
import * as https from 'https';
|
||||||
|
|
||||||
|
import { configService, SslConf } from '../config/env.config';
|
||||||
|
|
||||||
export class ServerUP {
|
export class ServerUP {
|
||||||
static #app: Express;
|
static #app: Express;
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ import {
|
|||||||
proto,
|
proto,
|
||||||
SignalDataTypeMap,
|
SignalDataTypeMap,
|
||||||
} from '@whiskeysockets/baileys';
|
} from '@whiskeysockets/baileys';
|
||||||
|
|
||||||
import { configService, Database } from '../config/env.config';
|
import { configService, Database } from '../config/env.config';
|
||||||
import { Logger } from '../config/logger.config';
|
import { Logger } from '../config/logger.config';
|
||||||
import { dbserver } from '../db/db.connect';
|
import { dbserver } from '../libs/db.connect';
|
||||||
|
|
||||||
export async function useMultiFileAuthStateDb(
|
export async function useMultiFileAuthStateDb(
|
||||||
coll: string,
|
coll: string,
|
||||||
@@ -24,12 +25,12 @@ export async function useMultiFileAuthStateDb(
|
|||||||
const writeData = async (data: any, key: string): Promise<any> => {
|
const writeData = async (data: any, key: string): Promise<any> => {
|
||||||
try {
|
try {
|
||||||
await client.connect();
|
await client.connect();
|
||||||
return await collection.replaceOne(
|
return await collection.replaceOne({ _id: key }, JSON.parse(JSON.stringify(data, BufferJSON.replacer)), {
|
||||||
{ _id: key },
|
upsert: true,
|
||||||
JSON.parse(JSON.stringify(data, BufferJSON.replacer)),
|
});
|
||||||
{ upsert: true },
|
} catch (error) {
|
||||||
);
|
logger.error(error);
|
||||||
} catch {}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const readData = async (key: string): Promise<any> => {
|
const readData = async (key: string): Promise<any> => {
|
||||||
@@ -38,14 +39,18 @@ export async function useMultiFileAuthStateDb(
|
|||||||
const data = await collection.findOne({ _id: key });
|
const data = await collection.findOne({ _id: key });
|
||||||
const creds = JSON.stringify(data);
|
const creds = JSON.stringify(data);
|
||||||
return JSON.parse(creds, BufferJSON.reviver);
|
return JSON.parse(creds, BufferJSON.reviver);
|
||||||
} catch {}
|
} catch (error) {
|
||||||
|
logger.error(error);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeData = async (key: string) => {
|
const removeData = async (key: string) => {
|
||||||
try {
|
try {
|
||||||
await client.connect();
|
await client.connect();
|
||||||
return await collection.deleteOne({ _id: key });
|
return await collection.deleteOne({ _id: key });
|
||||||
} catch {}
|
} catch (error) {
|
||||||
|
logger.error(error);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const creds: AuthenticationCreds = (await readData('creds')) || initAuthCreds();
|
const creds: AuthenticationCreds = (await readData('creds')) || initAuthCreds();
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import {
|
|||||||
proto,
|
proto,
|
||||||
SignalDataTypeMap,
|
SignalDataTypeMap,
|
||||||
} from '@whiskeysockets/baileys';
|
} from '@whiskeysockets/baileys';
|
||||||
import { RedisCache } from '../db/redis.client';
|
|
||||||
import { Logger } from '../config/logger.config';
|
import { Logger } from '../config/logger.config';
|
||||||
import { Redis } from '../config/env.config';
|
import { RedisCache } from '../libs/redis.client';
|
||||||
|
|
||||||
export async function useMultiFileAuthStateRedisDb(cache: RedisCache): Promise<{
|
export async function useMultiFileAuthStateRedisDb(cache: RedisCache): Promise<{
|
||||||
state: AuthenticationState;
|
state: AuthenticationState;
|
||||||
|
|||||||
@@ -508,6 +508,7 @@ export const archiveChatSchema: JSONSchema7 = {
|
|||||||
$id: v4(),
|
$id: v4(),
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
|
chat: { type: 'string' },
|
||||||
lastMessage: {
|
lastMessage: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
@@ -528,7 +529,7 @@ export const archiveChatSchema: JSONSchema7 = {
|
|||||||
},
|
},
|
||||||
archive: { type: 'boolean', enum: [true, false] },
|
archive: { type: 'boolean', enum: [true, false] },
|
||||||
},
|
},
|
||||||
required: ['lastMessage', 'archive'],
|
required: ['archive'],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const deleteMessageSchema: JSONSchema7 = {
|
export const deleteMessageSchema: JSONSchema7 = {
|
||||||
@@ -823,12 +824,81 @@ export const updateGroupDescriptionSchema: JSONSchema7 = {
|
|||||||
...isNotEmpty('groupJid', 'description'),
|
...isNotEmpty('groupJid', 'description'),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Webhook Schema
|
|
||||||
export const webhookSchema: JSONSchema7 = {
|
export const webhookSchema: JSONSchema7 = {
|
||||||
$id: v4(),
|
$id: v4(),
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
url: { type: 'string' },
|
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',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
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] },
|
||||||
|
reopen_conversation: { type: 'boolean', enum: [true, false] },
|
||||||
|
conversation_pending: { 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] },
|
enabled: { type: 'boolean', enum: [true, false] },
|
||||||
events: {
|
events: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
@@ -861,64 +931,95 @@ export const webhookSchema: JSONSchema7 = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
required: ['url', 'enabled'],
|
required: ['enabled'],
|
||||||
...isNotEmpty('url'),
|
...isNotEmpty('enabled'),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const chatwootSchema: JSONSchema7 = {
|
export const rabbitmqSchema: JSONSchema7 = {
|
||||||
$id: v4(),
|
$id: v4(),
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
enabled: { type: 'boolean', enum: [true, false] },
|
enabled: { type: 'boolean', enum: [true, false] },
|
||||||
account_id: { type: 'string' },
|
events: {
|
||||||
token: { type: 'string' },
|
type: 'array',
|
||||||
url: { type: 'string' },
|
minItems: 0,
|
||||||
sign_msg: { type: 'boolean', enum: [true, false] },
|
items: {
|
||||||
reopen_conversation: { type: 'boolean', enum: [true, false] },
|
type: 'string',
|
||||||
conversation_pending: { type: 'boolean', enum: [true, false] },
|
enum: [
|
||||||
},
|
'APPLICATION_STARTUP',
|
||||||
required: [
|
'QRCODE_UPDATED',
|
||||||
'enabled',
|
'MESSAGES_SET',
|
||||||
'account_id',
|
'MESSAGES_UPSERT',
|
||||||
'token',
|
'MESSAGES_UPDATE',
|
||||||
'url',
|
'MESSAGES_DELETE',
|
||||||
'sign_msg',
|
'SEND_MESSAGE',
|
||||||
'reopen_conversation',
|
'CONTACTS_SET',
|
||||||
'conversation_pending',
|
'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',
|
||||||
],
|
],
|
||||||
...isNotEmpty(
|
},
|
||||||
'account_id',
|
},
|
||||||
'token',
|
},
|
||||||
'url',
|
required: ['enabled'],
|
||||||
'sign_msg',
|
...isNotEmpty('enabled'),
|
||||||
'reopen_conversation',
|
|
||||||
'conversation_pending',
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const settingsSchema: JSONSchema7 = {
|
export const typebotSchema: JSONSchema7 = {
|
||||||
$id: v4(),
|
$id: v4(),
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
reject_call: { type: 'boolean', enum: [true, false] },
|
enabled: { type: 'boolean', enum: [true, false] },
|
||||||
msg_call: { type: 'string' },
|
url: { type: 'string' },
|
||||||
groups_ignore: { type: 'boolean', enum: [true, false] },
|
typebot: { type: 'string' },
|
||||||
always_online: { type: 'boolean', enum: [true, false] },
|
expire: { type: 'integer' },
|
||||||
read_messages: { type: 'boolean', enum: [true, false] },
|
delay_message: { type: 'integer' },
|
||||||
read_status: { type: 'boolean', enum: [true, false] },
|
unknown_message: { type: 'string' },
|
||||||
},
|
},
|
||||||
required: [
|
required: ['enabled', 'url', 'typebot', 'expire'],
|
||||||
'reject_call',
|
...isNotEmpty('enabled', 'url', 'typebot', 'expire'),
|
||||||
'groups_ignore',
|
};
|
||||||
'always_online',
|
|
||||||
'read_messages',
|
export const typebotStatusSchema: JSONSchema7 = {
|
||||||
'read_status',
|
$id: v4(),
|
||||||
],
|
type: 'object',
|
||||||
...isNotEmpty(
|
properties: {
|
||||||
'reject_call',
|
remoteJid: { type: 'string' },
|
||||||
'groups_ignore',
|
status: { type: 'string', enum: ['opened', 'closed', 'paused'] },
|
||||||
'always_online',
|
},
|
||||||
'read_messages',
|
required: ['remoteJid', 'status'],
|
||||||
'read_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'),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
|
||||||
import { ConfigService, Database } from '../../config/env.config';
|
import { ConfigService, Database } from '../../config/env.config';
|
||||||
import { ROOT_DIR } from '../../config/path.config';
|
import { ROOT_DIR } from '../../config/path.config';
|
||||||
|
|
||||||
@@ -34,11 +35,9 @@ export abstract class Repository implements IRepository {
|
|||||||
mkdirSync(create.path, { recursive: true });
|
mkdirSync(create.path, { recursive: true });
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
writeFileSync(
|
writeFileSync(join(create.path, create.fileName + '.json'), JSON.stringify({ ...create.data }), {
|
||||||
join(create.path, create.fileName + '.json'),
|
encoding: 'utf-8',
|
||||||
JSON.stringify({ ...create.data }),
|
});
|
||||||
{ encoding: 'utf-8' },
|
|
||||||
);
|
|
||||||
|
|
||||||
return { message: 'create - success' };
|
return { message: 'create - success' };
|
||||||
} finally {
|
} finally {
|
||||||
@@ -46,18 +45,22 @@ export abstract class Repository implements IRepository {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
public insert(data: any, instanceName: string, saveDb = false): Promise<IInsert> {
|
public insert(data: any, instanceName: string, saveDb = false): Promise<IInsert> {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
public update(data: any, instanceName: string, saveDb = false): Promise<IInsert> {
|
public update(data: any, instanceName: string, saveDb = false): Promise<IInsert> {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
public find(query: any): Promise<any> {
|
public find(query: any): Promise<any> {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
delete(query: any, force?: boolean): Promise<any> {
|
delete(query: any, force?: boolean): Promise<any> {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import { InstanceDto } from '../dto/instance.dto';
|
|
||||||
import { JSONSchema7 } from 'json-schema';
|
|
||||||
import { Request } from 'express';
|
|
||||||
import { validate } from 'jsonschema';
|
|
||||||
import { BadRequestException } from '../../exceptions';
|
|
||||||
import 'express-async-errors';
|
import 'express-async-errors';
|
||||||
|
|
||||||
|
import { Request } from 'express';
|
||||||
|
import { JSONSchema7 } from 'json-schema';
|
||||||
|
import { validate } from 'jsonschema';
|
||||||
|
|
||||||
import { Logger } from '../../config/logger.config';
|
import { Logger } from '../../config/logger.config';
|
||||||
import { GetParticipant, GroupInvite, GroupJid } from '../dto/group.dto';
|
import { BadRequestException } from '../../exceptions';
|
||||||
|
import { GetParticipant, GroupInvite } from '../dto/group.dto';
|
||||||
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
|
|
||||||
type DataValidate<T> = {
|
type DataValidate<T> = {
|
||||||
request: Request;
|
request: Request;
|
||||||
@@ -46,20 +48,21 @@ export abstract class RouterBroker {
|
|||||||
const v = schema ? validate(ref, schema) : { valid: true, errors: [] };
|
const v = schema ? validate(ref, schema) : { valid: true, errors: [] };
|
||||||
|
|
||||||
if (!v.valid) {
|
if (!v.valid) {
|
||||||
const message: any[] = v.errors.map(({ property, stack, schema }) => {
|
const message: any[] = v.errors.map(({ stack, schema }) => {
|
||||||
let message: string;
|
let message: string;
|
||||||
if (schema['description']) {
|
if (schema['description']) {
|
||||||
message = schema['description'];
|
message = schema['description'];
|
||||||
} else {
|
} else {
|
||||||
message = stack.replace('instance.', '');
|
message = stack.replace('instance.', '');
|
||||||
}
|
}
|
||||||
return {
|
return message;
|
||||||
property: property.replace('instance.', ''),
|
// return {
|
||||||
message,
|
// property: property.replace('instance.', ''),
|
||||||
};
|
// message,
|
||||||
|
// };
|
||||||
});
|
});
|
||||||
logger.error([...message]);
|
logger.error(message);
|
||||||
throw new BadRequestException(...message);
|
throw new BadRequestException(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
return await execute(instance, ref);
|
return await execute(instance, ref);
|
||||||
@@ -99,21 +102,29 @@ export abstract class RouterBroker {
|
|||||||
public async groupValidate<T>(args: DataValidate<T>) {
|
public async groupValidate<T>(args: DataValidate<T>) {
|
||||||
const { request, ClassRef, schema, execute } = args;
|
const { request, ClassRef, schema, execute } = args;
|
||||||
|
|
||||||
const groupJid = request.query as unknown as GroupJid;
|
|
||||||
|
|
||||||
if (!groupJid?.groupJid) {
|
|
||||||
throw new BadRequestException(
|
|
||||||
'The group id needs to be informed in the query',
|
|
||||||
'ex: "groupJid=120362@g.us"',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const instance = request.params as unknown as InstanceDto;
|
const instance = request.params as unknown as InstanceDto;
|
||||||
const body = request.body;
|
const body = request.body;
|
||||||
|
|
||||||
|
let groupJid = body?.groupJid;
|
||||||
|
|
||||||
|
if (!groupJid) {
|
||||||
|
if (request.query?.groupJid) {
|
||||||
|
groupJid = request.query.groupJid;
|
||||||
|
} else {
|
||||||
|
throw new BadRequestException('The group id needs to be informed in the query', 'ex: "groupJid=120362@g.us"');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!groupJid.endsWith('@g.us')) {
|
||||||
|
groupJid = groupJid + '@g.us';
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(body, {
|
||||||
|
groupJid: groupJid,
|
||||||
|
});
|
||||||
|
|
||||||
const ref = new ClassRef();
|
const ref = new ClassRef();
|
||||||
|
|
||||||
Object.assign(body, groupJid);
|
|
||||||
Object.assign(ref, body);
|
Object.assign(ref, body);
|
||||||
|
|
||||||
const v = validate(ref, schema);
|
const v = validate(ref, schema);
|
||||||
@@ -186,9 +197,7 @@ export abstract class RouterBroker {
|
|||||||
const getParticipants = request.query as unknown as GetParticipant;
|
const getParticipants = request.query as unknown as GetParticipant;
|
||||||
|
|
||||||
if (!getParticipants?.getParticipants) {
|
if (!getParticipants?.getParticipants) {
|
||||||
throw new BadRequestException(
|
throw new BadRequestException('The getParticipants needs to be informed in the query');
|
||||||
'The getParticipants needs to be informed in the query',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const instance = request.params as unknown as InstanceDto;
|
const instance = request.params as unknown as InstanceDto;
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { proto } from '@whiskeysockets/baileys';
|
import { Logger } from '../../config/logger.config';
|
||||||
import {
|
import {
|
||||||
ArchiveChatDto,
|
ArchiveChatDto,
|
||||||
DeleteMessage,
|
DeleteMessage,
|
||||||
|
getBase64FromMediaMessageDto,
|
||||||
NumberDto,
|
NumberDto,
|
||||||
PrivacySettingDto,
|
PrivacySettingDto,
|
||||||
ProfileNameDto,
|
ProfileNameDto,
|
||||||
@@ -9,14 +10,12 @@ import {
|
|||||||
ProfileStatusDto,
|
ProfileStatusDto,
|
||||||
ReadMessageDto,
|
ReadMessageDto,
|
||||||
WhatsAppNumberDto,
|
WhatsAppNumberDto,
|
||||||
getBase64FromMediaMessageDto,
|
|
||||||
} from '../dto/chat.dto';
|
} from '../dto/chat.dto';
|
||||||
import { InstanceDto } from '../dto/instance.dto';
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
import { ContactQuery } from '../repository/contact.repository';
|
import { ContactQuery } from '../repository/contact.repository';
|
||||||
import { MessageQuery } from '../repository/message.repository';
|
import { MessageQuery } from '../repository/message.repository';
|
||||||
import { MessageUpQuery } from '../repository/messageUp.repository';
|
import { MessageUpQuery } from '../repository/messageUp.repository';
|
||||||
import { WAMonitoringService } from '../services/monitor.service';
|
import { WAMonitoringService } from '../services/monitor.service';
|
||||||
import { Logger } from '../../config/logger.config';
|
|
||||||
|
|
||||||
const logger = new Logger('ChatController');
|
const logger = new Logger('ChatController');
|
||||||
|
|
||||||
@@ -50,10 +49,7 @@ export class ChatController {
|
|||||||
|
|
||||||
public async fetchProfile({ instanceName }: InstanceDto, data: NumberDto) {
|
public async fetchProfile({ instanceName }: InstanceDto, data: NumberDto) {
|
||||||
logger.verbose('requested fetchProfile from ' + instanceName + ' instance');
|
logger.verbose('requested fetchProfile from ' + instanceName + ' instance');
|
||||||
return await this.waMonitor.waInstances[instanceName].fetchProfile(
|
return await this.waMonitor.waInstances[instanceName].fetchProfile(instanceName, data.number);
|
||||||
instanceName,
|
|
||||||
data.number,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async fetchContacts({ instanceName }: InstanceDto, query: ContactQuery) {
|
public async fetchContacts({ instanceName }: InstanceDto, query: ContactQuery) {
|
||||||
@@ -61,13 +57,8 @@ export class ChatController {
|
|||||||
return await this.waMonitor.waInstances[instanceName].fetchContacts(query);
|
return await this.waMonitor.waInstances[instanceName].fetchContacts(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getBase64FromMediaMessage(
|
public async getBase64FromMediaMessage({ instanceName }: InstanceDto, data: getBase64FromMediaMessageDto) {
|
||||||
{ instanceName }: InstanceDto,
|
logger.verbose('requested getBase64FromMediaMessage from ' + instanceName + ' instance');
|
||||||
data: getBase64FromMediaMessageDto,
|
|
||||||
) {
|
|
||||||
logger.verbose(
|
|
||||||
'requested getBase64FromMediaMessage from ' + instanceName + ' instance',
|
|
||||||
);
|
|
||||||
return await this.waMonitor.waInstances[instanceName].getBase64FromMediaMessage(data);
|
return await this.waMonitor.waInstances[instanceName].getBase64FromMediaMessage(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,22 +82,14 @@ export class ChatController {
|
|||||||
return await this.waMonitor.waInstances[instanceName].fetchPrivacySettings();
|
return await this.waMonitor.waInstances[instanceName].fetchPrivacySettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updatePrivacySettings(
|
public async updatePrivacySettings({ instanceName }: InstanceDto, data: PrivacySettingDto) {
|
||||||
{ instanceName }: InstanceDto,
|
|
||||||
data: PrivacySettingDto,
|
|
||||||
) {
|
|
||||||
logger.verbose('requested updatePrivacySettings from ' + instanceName + ' instance');
|
logger.verbose('requested updatePrivacySettings from ' + instanceName + ' instance');
|
||||||
return await this.waMonitor.waInstances[instanceName].updatePrivacySettings(data);
|
return await this.waMonitor.waInstances[instanceName].updatePrivacySettings(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async fetchBusinessProfile(
|
public async fetchBusinessProfile({ instanceName }: InstanceDto, data: ProfilePictureDto) {
|
||||||
{ instanceName }: InstanceDto,
|
|
||||||
data: ProfilePictureDto,
|
|
||||||
) {
|
|
||||||
logger.verbose('requested fetchBusinessProfile from ' + instanceName + ' instance');
|
logger.verbose('requested fetchBusinessProfile from ' + instanceName + ' instance');
|
||||||
return await this.waMonitor.waInstances[instanceName].fetchBusinessProfile(
|
return await this.waMonitor.waInstances[instanceName].fetchBusinessProfile(data.number);
|
||||||
data.number,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updateProfileName({ instanceName }: InstanceDto, data: ProfileNameDto) {
|
public async updateProfileName({ instanceName }: InstanceDto, data: ProfileNameDto) {
|
||||||
@@ -114,30 +97,17 @@ export class ChatController {
|
|||||||
return await this.waMonitor.waInstances[instanceName].updateProfileName(data.name);
|
return await this.waMonitor.waInstances[instanceName].updateProfileName(data.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updateProfileStatus(
|
public async updateProfileStatus({ instanceName }: InstanceDto, data: ProfileStatusDto) {
|
||||||
{ instanceName }: InstanceDto,
|
|
||||||
data: ProfileStatusDto,
|
|
||||||
) {
|
|
||||||
logger.verbose('requested updateProfileStatus from ' + instanceName + ' instance');
|
logger.verbose('requested updateProfileStatus from ' + instanceName + ' instance');
|
||||||
return await this.waMonitor.waInstances[instanceName].updateProfileStatus(
|
return await this.waMonitor.waInstances[instanceName].updateProfileStatus(data.status);
|
||||||
data.status,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updateProfilePicture(
|
public async updateProfilePicture({ instanceName }: InstanceDto, data: ProfilePictureDto) {
|
||||||
{ instanceName }: InstanceDto,
|
|
||||||
data: ProfilePictureDto,
|
|
||||||
) {
|
|
||||||
logger.verbose('requested updateProfilePicture from ' + instanceName + ' instance');
|
logger.verbose('requested updateProfilePicture from ' + instanceName + ' instance');
|
||||||
return await this.waMonitor.waInstances[instanceName].updateProfilePicture(
|
return await this.waMonitor.waInstances[instanceName].updateProfilePicture(data.picture);
|
||||||
data.picture,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async removeProfilePicture(
|
public async removeProfilePicture({ instanceName }: InstanceDto) {
|
||||||
{ instanceName }: InstanceDto,
|
|
||||||
data: ProfilePictureDto,
|
|
||||||
) {
|
|
||||||
logger.verbose('requested removeProfilePicture from ' + instanceName + ' instance');
|
logger.verbose('requested removeProfilePicture from ' + instanceName + ' instance');
|
||||||
return await this.waMonitor.waInstances[instanceName].removeProfilePicture();
|
return await this.waMonitor.waInstances[instanceName].removeProfilePicture();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,20 @@
|
|||||||
import { isURL } from 'class-validator';
|
import { isURL } from 'class-validator';
|
||||||
import { BadRequestException } from '../../exceptions';
|
|
||||||
import { InstanceDto } from '../dto/instance.dto';
|
|
||||||
import { ChatwootDto } from '../dto/chatwoot.dto';
|
|
||||||
import { ChatwootService } from '../services/chatwoot.service';
|
|
||||||
import { Logger } from '../../config/logger.config';
|
|
||||||
import { waMonitor } from '../whatsapp.module';
|
|
||||||
import { ConfigService, HttpServer } from '../../config/env.config';
|
import { ConfigService, HttpServer } from '../../config/env.config';
|
||||||
|
import { Logger } from '../../config/logger.config';
|
||||||
|
import { BadRequestException } from '../../exceptions';
|
||||||
|
import { ChatwootDto } from '../dto/chatwoot.dto';
|
||||||
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
|
import { ChatwootService } from '../services/chatwoot.service';
|
||||||
|
import { waMonitor } from '../whatsapp.module';
|
||||||
|
|
||||||
const logger = new Logger('ChatwootController');
|
const logger = new Logger('ChatwootController');
|
||||||
|
|
||||||
export class ChatwootController {
|
export class ChatwootController {
|
||||||
constructor(
|
constructor(private readonly chatwootService: ChatwootService, private readonly configService: ConfigService) {}
|
||||||
private readonly chatwootService: ChatwootService,
|
|
||||||
private readonly configService: ConfigService,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
public async createChatwoot(instance: InstanceDto, data: ChatwootDto) {
|
public async createChatwoot(instance: InstanceDto, data: ChatwootDto) {
|
||||||
logger.verbose(
|
logger.verbose('requested createChatwoot from ' + instance.instanceName + ' instance');
|
||||||
'requested createChatwoot from ' + instance.instanceName + ' instance',
|
|
||||||
);
|
|
||||||
|
|
||||||
if (data.enabled) {
|
if (data.enabled) {
|
||||||
if (!isURL(data.url, { require_tld: false })) {
|
if (!isURL(data.url, { require_tld: false })) {
|
||||||
@@ -56,7 +52,7 @@ export class ChatwootController {
|
|||||||
|
|
||||||
const response = {
|
const response = {
|
||||||
...result,
|
...result,
|
||||||
webhook_url: `${urlServer}/chatwoot/webhook/${instance.instanceName}`,
|
webhook_url: `${urlServer}/chatwoot/webhook/${encodeURIComponent(instance.instanceName)}`,
|
||||||
};
|
};
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
@@ -82,24 +78,16 @@ export class ChatwootController {
|
|||||||
|
|
||||||
const response = {
|
const response = {
|
||||||
...result,
|
...result,
|
||||||
webhook_url: `${urlServer}/chatwoot/webhook/${instance.instanceName}`,
|
webhook_url: `${urlServer}/chatwoot/webhook/${encodeURIComponent(instance.instanceName)}`,
|
||||||
};
|
};
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async receiveWebhook(instance: InstanceDto, data: any) {
|
public async receiveWebhook(instance: InstanceDto, data: any) {
|
||||||
logger.verbose(
|
logger.verbose('requested receiveWebhook from ' + instance.instanceName + ' instance');
|
||||||
'requested receiveWebhook from ' + instance.instanceName + ' instance',
|
|
||||||
);
|
|
||||||
const chatwootService = new ChatwootService(waMonitor, this.configService);
|
const chatwootService = new ChatwootService(waMonitor, this.configService);
|
||||||
|
|
||||||
return chatwootService.receiveWebhook(instance, data);
|
return chatwootService.receiveWebhook(instance, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async newInstance(data: any) {
|
|
||||||
const chatwootService = new ChatwootService(waMonitor, this.configService);
|
|
||||||
|
|
||||||
return chatwootService.newInstance(data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { Logger } from '../../config/logger.config';
|
||||||
import {
|
import {
|
||||||
CreateGroupDto,
|
CreateGroupDto,
|
||||||
GetParticipant,
|
GetParticipant,
|
||||||
@@ -13,7 +14,6 @@ import {
|
|||||||
} from '../dto/group.dto';
|
} from '../dto/group.dto';
|
||||||
import { InstanceDto } from '../dto/instance.dto';
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
import { WAMonitoringService } from '../services/monitor.service';
|
import { WAMonitoringService } from '../services/monitor.service';
|
||||||
import { Logger } from '../../config/logger.config';
|
|
||||||
|
|
||||||
const logger = new Logger('ChatController');
|
const logger = new Logger('ChatController');
|
||||||
|
|
||||||
@@ -26,33 +26,18 @@ export class GroupController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async updateGroupPicture(instance: InstanceDto, update: GroupPictureDto) {
|
public async updateGroupPicture(instance: InstanceDto, update: GroupPictureDto) {
|
||||||
logger.verbose(
|
logger.verbose('requested updateGroupPicture from ' + instance.instanceName + ' instance');
|
||||||
'requested updateGroupPicture from ' + instance.instanceName + ' instance',
|
return await this.waMonitor.waInstances[instance.instanceName].updateGroupPicture(update);
|
||||||
);
|
|
||||||
return await this.waMonitor.waInstances[instance.instanceName].updateGroupPicture(
|
|
||||||
update,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updateGroupSubject(instance: InstanceDto, update: GroupSubjectDto) {
|
public async updateGroupSubject(instance: InstanceDto, update: GroupSubjectDto) {
|
||||||
logger.verbose(
|
logger.verbose('requested updateGroupSubject from ' + instance.instanceName + ' instance');
|
||||||
'requested updateGroupSubject from ' + instance.instanceName + ' instance',
|
return await this.waMonitor.waInstances[instance.instanceName].updateGroupSubject(update);
|
||||||
);
|
|
||||||
return await this.waMonitor.waInstances[instance.instanceName].updateGroupSubject(
|
|
||||||
update,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updateGroupDescription(
|
public async updateGroupDescription(instance: InstanceDto, update: GroupDescriptionDto) {
|
||||||
instance: InstanceDto,
|
logger.verbose('requested updateGroupDescription from ' + instance.instanceName + ' instance');
|
||||||
update: GroupDescriptionDto,
|
return await this.waMonitor.waInstances[instance.instanceName].updateGroupDescription(update);
|
||||||
) {
|
|
||||||
logger.verbose(
|
|
||||||
'requested updateGroupDescription from ' + instance.instanceName + ' instance',
|
|
||||||
);
|
|
||||||
return await this.waMonitor.waInstances[instance.instanceName].updateGroupDescription(
|
|
||||||
update,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async findGroupInfo(instance: InstanceDto, groupJid: GroupJid) {
|
public async findGroupInfo(instance: InstanceDto, groupJid: GroupJid) {
|
||||||
@@ -61,12 +46,8 @@ export class GroupController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async fetchAllGroups(instance: InstanceDto, getPaticipants: GetParticipant) {
|
public async fetchAllGroups(instance: InstanceDto, getPaticipants: GetParticipant) {
|
||||||
logger.verbose(
|
logger.verbose('requested fetchAllGroups from ' + instance.instanceName + ' instance');
|
||||||
'requested fetchAllGroups from ' + instance.instanceName + ' instance',
|
return await this.waMonitor.waInstances[instance.instanceName].fetchAllGroups(getPaticipants);
|
||||||
);
|
|
||||||
return await this.waMonitor.waInstances[instance.instanceName].fetchAllGroups(
|
|
||||||
getPaticipants,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async inviteCode(instance: InstanceDto, groupJid: GroupJid) {
|
public async inviteCode(instance: InstanceDto, groupJid: GroupJid) {
|
||||||
@@ -85,49 +66,28 @@ export class GroupController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async revokeInviteCode(instance: InstanceDto, groupJid: GroupJid) {
|
public async revokeInviteCode(instance: InstanceDto, groupJid: GroupJid) {
|
||||||
logger.verbose(
|
logger.verbose('requested revokeInviteCode from ' + instance.instanceName + ' instance');
|
||||||
'requested revokeInviteCode from ' + instance.instanceName + ' instance',
|
return await this.waMonitor.waInstances[instance.instanceName].revokeInviteCode(groupJid);
|
||||||
);
|
|
||||||
return await this.waMonitor.waInstances[instance.instanceName].revokeInviteCode(
|
|
||||||
groupJid,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async findParticipants(instance: InstanceDto, groupJid: GroupJid) {
|
public async findParticipants(instance: InstanceDto, groupJid: GroupJid) {
|
||||||
logger.verbose(
|
logger.verbose('requested findParticipants from ' + instance.instanceName + ' instance');
|
||||||
'requested findParticipants from ' + instance.instanceName + ' instance',
|
return await this.waMonitor.waInstances[instance.instanceName].findParticipants(groupJid);
|
||||||
);
|
|
||||||
return await this.waMonitor.waInstances[instance.instanceName].findParticipants(
|
|
||||||
groupJid,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updateGParticipate(
|
public async updateGParticipate(instance: InstanceDto, update: GroupUpdateParticipantDto) {
|
||||||
instance: InstanceDto,
|
logger.verbose('requested updateGParticipate from ' + instance.instanceName + ' instance');
|
||||||
update: GroupUpdateParticipantDto,
|
return await this.waMonitor.waInstances[instance.instanceName].updateGParticipant(update);
|
||||||
) {
|
|
||||||
logger.verbose(
|
|
||||||
'requested updateGParticipate from ' + instance.instanceName + ' instance',
|
|
||||||
);
|
|
||||||
return await this.waMonitor.waInstances[instance.instanceName].updateGParticipant(
|
|
||||||
update,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updateGSetting(instance: InstanceDto, update: GroupUpdateSettingDto) {
|
public async updateGSetting(instance: InstanceDto, update: GroupUpdateSettingDto) {
|
||||||
logger.verbose(
|
logger.verbose('requested updateGSetting from ' + instance.instanceName + ' instance');
|
||||||
'requested updateGSetting from ' + instance.instanceName + ' instance',
|
|
||||||
);
|
|
||||||
return await this.waMonitor.waInstances[instance.instanceName].updateGSetting(update);
|
return await this.waMonitor.waInstances[instance.instanceName].updateGSetting(update);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async toggleEphemeral(instance: InstanceDto, update: GroupToggleEphemeralDto) {
|
public async toggleEphemeral(instance: InstanceDto, update: GroupToggleEphemeralDto) {
|
||||||
logger.verbose(
|
logger.verbose('requested toggleEphemeral from ' + instance.instanceName + ' instance');
|
||||||
'requested toggleEphemeral from ' + instance.instanceName + ' instance',
|
return await this.waMonitor.waInstances[instance.instanceName].toggleEphemeral(update);
|
||||||
);
|
|
||||||
return await this.waMonitor.waInstances[instance.instanceName].toggleEphemeral(
|
|
||||||
update,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async leaveGroup(instance: InstanceDto, groupJid: GroupJid) {
|
public async leaveGroup(instance: InstanceDto, groupJid: GroupJid) {
|
||||||
|
|||||||
@@ -1,19 +1,23 @@
|
|||||||
import { delay } from '@whiskeysockets/baileys';
|
import { delay } from '@whiskeysockets/baileys';
|
||||||
|
import { isURL } from 'class-validator';
|
||||||
import EventEmitter2 from 'eventemitter2';
|
import EventEmitter2 from 'eventemitter2';
|
||||||
import { Auth, ConfigService, HttpServer } from '../../config/env.config';
|
|
||||||
|
import { ConfigService, HttpServer } from '../../config/env.config';
|
||||||
|
import { Logger } from '../../config/logger.config';
|
||||||
import { BadRequestException, InternalServerErrorException } from '../../exceptions';
|
import { BadRequestException, InternalServerErrorException } from '../../exceptions';
|
||||||
|
import { RedisCache } from '../../libs/redis.client';
|
||||||
import { InstanceDto } from '../dto/instance.dto';
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
import { RepositoryBroker } from '../repository/repository.manager';
|
import { RepositoryBroker } from '../repository/repository.manager';
|
||||||
import { AuthService, OldToken } from '../services/auth.service';
|
import { AuthService, OldToken } from '../services/auth.service';
|
||||||
import { WAMonitoringService } from '../services/monitor.service';
|
|
||||||
import { WAStartupService } from '../services/whatsapp.service';
|
|
||||||
import { WebhookService } from '../services/webhook.service';
|
|
||||||
import { ChatwootService } from '../services/chatwoot.service';
|
import { ChatwootService } from '../services/chatwoot.service';
|
||||||
import { Logger } from '../../config/logger.config';
|
import { WAMonitoringService } from '../services/monitor.service';
|
||||||
import { wa } from '../types/wa.types';
|
import { RabbitmqService } from '../services/rabbitmq.service';
|
||||||
import { RedisCache } from '../../db/redis.client';
|
|
||||||
import { isURL } from 'class-validator';
|
|
||||||
import { SettingsService } from '../services/settings.service';
|
import { SettingsService } from '../services/settings.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';
|
||||||
|
|
||||||
export class InstanceController {
|
export class InstanceController {
|
||||||
constructor(
|
constructor(
|
||||||
@@ -25,6 +29,9 @@ export class InstanceController {
|
|||||||
private readonly webhookService: WebhookService,
|
private readonly webhookService: WebhookService,
|
||||||
private readonly chatwootService: ChatwootService,
|
private readonly chatwootService: ChatwootService,
|
||||||
private readonly settingsService: SettingsService,
|
private readonly settingsService: SettingsService,
|
||||||
|
private readonly websocketService: WebsocketService,
|
||||||
|
private readonly rabbitmqService: RabbitmqService,
|
||||||
|
private readonly typebotService: TypebotService,
|
||||||
private readonly cache: RedisCache,
|
private readonly cache: RedisCache,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@@ -50,30 +57,26 @@ export class InstanceController {
|
|||||||
always_online,
|
always_online,
|
||||||
read_messages,
|
read_messages,
|
||||||
read_status,
|
read_status,
|
||||||
|
websocket_enabled,
|
||||||
|
websocket_events,
|
||||||
|
rabbitmq_enabled,
|
||||||
|
rabbitmq_events,
|
||||||
|
typebot_url,
|
||||||
|
typebot,
|
||||||
|
typebot_expire,
|
||||||
|
typebot_keyword_finish,
|
||||||
|
typebot_delay_message,
|
||||||
|
typebot_unknown_message,
|
||||||
}: InstanceDto) {
|
}: InstanceDto) {
|
||||||
try {
|
try {
|
||||||
this.logger.verbose('requested createInstance from ' + instanceName + ' instance');
|
this.logger.verbose('requested createInstance from ' + instanceName + ' instance');
|
||||||
|
|
||||||
if (instanceName !== instanceName.toLowerCase().replace(/[^a-z0-9]/g, '')) {
|
|
||||||
throw new BadRequestException(
|
|
||||||
'The instance name must be lowercase and without special characters',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.logger.verbose('checking duplicate token');
|
this.logger.verbose('checking duplicate token');
|
||||||
await this.authService.checkDuplicateToken(token);
|
await this.authService.checkDuplicateToken(token);
|
||||||
|
|
||||||
this.logger.verbose('creating instance');
|
this.logger.verbose('creating instance');
|
||||||
const instance = new WAStartupService(
|
const instance = new WAStartupService(this.configService, this.eventEmitter, this.repository, this.cache);
|
||||||
this.configService,
|
instance.instanceName = instanceName;
|
||||||
this.eventEmitter,
|
|
||||||
this.repository,
|
|
||||||
this.cache,
|
|
||||||
);
|
|
||||||
instance.instanceName = instanceName
|
|
||||||
.toLowerCase()
|
|
||||||
.replace(/[^a-z0-9]/g, '')
|
|
||||||
.replace(' ', '');
|
|
||||||
|
|
||||||
this.logger.verbose('instance: ' + instance.instanceName + ' created');
|
this.logger.verbose('instance: ' + instance.instanceName + ' created');
|
||||||
|
|
||||||
@@ -90,7 +93,7 @@ export class InstanceController {
|
|||||||
|
|
||||||
this.logger.verbose('hash: ' + hash + ' generated');
|
this.logger.verbose('hash: ' + hash + ' generated');
|
||||||
|
|
||||||
let getEvents: string[];
|
let webhookEvents: string[];
|
||||||
|
|
||||||
if (webhook) {
|
if (webhook) {
|
||||||
if (!isURL(webhook, { require_tld: false })) {
|
if (!isURL(webhook, { require_tld: false })) {
|
||||||
@@ -99,14 +102,152 @@ export class InstanceController {
|
|||||||
|
|
||||||
this.logger.verbose('creating webhook');
|
this.logger.verbose('creating webhook');
|
||||||
try {
|
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',
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
newEvents = events;
|
||||||
|
}
|
||||||
this.webhookService.create(instance, {
|
this.webhookService.create(instance, {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
url: webhook,
|
url: webhook,
|
||||||
events,
|
events: newEvents,
|
||||||
webhook_by_events,
|
webhook_by_events,
|
||||||
});
|
});
|
||||||
|
|
||||||
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',
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
newEvents = 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',
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
newEvents = events;
|
||||||
|
}
|
||||||
|
this.rabbitmqService.create(instance, {
|
||||||
|
enabled: true,
|
||||||
|
events: newEvents,
|
||||||
|
});
|
||||||
|
|
||||||
|
rabbitmqEvents = (await this.rabbitmqService.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,
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.log(error);
|
this.logger.log(error);
|
||||||
}
|
}
|
||||||
@@ -142,9 +283,28 @@ export class InstanceController {
|
|||||||
status: 'created',
|
status: 'created',
|
||||||
},
|
},
|
||||||
hash,
|
hash,
|
||||||
|
webhook: {
|
||||||
webhook,
|
webhook,
|
||||||
webhook_by_events,
|
webhook_by_events,
|
||||||
events: getEvents,
|
events: webhookEvents,
|
||||||
|
},
|
||||||
|
websocket: {
|
||||||
|
enabled: websocket_enabled,
|
||||||
|
events: websocketEvents,
|
||||||
|
},
|
||||||
|
rabbitmq: {
|
||||||
|
enabled: rabbitmq_enabled,
|
||||||
|
events: rabbitmqEvents,
|
||||||
|
},
|
||||||
|
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,
|
||||||
|
},
|
||||||
settings,
|
settings,
|
||||||
qrcode: getQrcode,
|
qrcode: getQrcode,
|
||||||
};
|
};
|
||||||
@@ -175,17 +335,11 @@ export class InstanceController {
|
|||||||
throw new BadRequestException('sign_msg is required');
|
throw new BadRequestException('sign_msg is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (chatwoot_reopen_conversation !== true && chatwoot_reopen_conversation !== false) {
|
||||||
chatwoot_reopen_conversation !== true &&
|
|
||||||
chatwoot_reopen_conversation !== false
|
|
||||||
) {
|
|
||||||
throw new BadRequestException('reopen_conversation is required');
|
throw new BadRequestException('reopen_conversation is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (chatwoot_conversation_pending !== true && chatwoot_conversation_pending !== false) {
|
||||||
chatwoot_conversation_pending !== true &&
|
|
||||||
chatwoot_conversation_pending !== false
|
|
||||||
) {
|
|
||||||
throw new BadRequestException('conversation_pending is required');
|
throw new BadRequestException('conversation_pending is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,7 +352,7 @@ export class InstanceController {
|
|||||||
token: chatwoot_token,
|
token: chatwoot_token,
|
||||||
url: chatwoot_url,
|
url: chatwoot_url,
|
||||||
sign_msg: chatwoot_sign_msg || false,
|
sign_msg: chatwoot_sign_msg || false,
|
||||||
name_inbox: instance.instanceName,
|
name_inbox: instance.instanceName.split('-cwId-')[0],
|
||||||
number,
|
number,
|
||||||
reopen_conversation: chatwoot_reopen_conversation || false,
|
reopen_conversation: chatwoot_reopen_conversation || false,
|
||||||
conversation_pending: chatwoot_conversation_pending || false,
|
conversation_pending: chatwoot_conversation_pending || false,
|
||||||
@@ -206,8 +360,8 @@ export class InstanceController {
|
|||||||
|
|
||||||
this.chatwootService.initInstanceChatwoot(
|
this.chatwootService.initInstanceChatwoot(
|
||||||
instance,
|
instance,
|
||||||
instance.instanceName,
|
instance.instanceName.split('-cwId-')[0],
|
||||||
`${urlServer}/chatwoot/webhook/${instance.instanceName}`,
|
`${urlServer}/chatwoot/webhook/${encodeURIComponent(instance.instanceName)}`,
|
||||||
qrcode,
|
qrcode,
|
||||||
number,
|
number,
|
||||||
);
|
);
|
||||||
@@ -221,9 +375,28 @@ export class InstanceController {
|
|||||||
status: 'created',
|
status: 'created',
|
||||||
},
|
},
|
||||||
hash,
|
hash,
|
||||||
|
webhook: {
|
||||||
webhook,
|
webhook,
|
||||||
webhook_by_events,
|
webhook_by_events,
|
||||||
events: getEvents,
|
events: webhookEvents,
|
||||||
|
},
|
||||||
|
websocket: {
|
||||||
|
enabled: websocket_enabled,
|
||||||
|
events: websocketEvents,
|
||||||
|
},
|
||||||
|
rabbitmq: {
|
||||||
|
enabled: rabbitmq_enabled,
|
||||||
|
events: rabbitmqEvents,
|
||||||
|
},
|
||||||
|
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,
|
||||||
|
},
|
||||||
settings,
|
settings,
|
||||||
chatwoot: {
|
chatwoot: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
@@ -235,26 +408,28 @@ export class InstanceController {
|
|||||||
conversation_pending: chatwoot_conversation_pending || false,
|
conversation_pending: chatwoot_conversation_pending || false,
|
||||||
number,
|
number,
|
||||||
name_inbox: instance.instanceName,
|
name_inbox: instance.instanceName,
|
||||||
webhook_url: `${urlServer}/chatwoot/webhook/${instance.instanceName}`,
|
webhook_url: `${urlServer}/chatwoot/webhook/${encodeURIComponent(instance.instanceName)}`,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
this.logger.error(error.message[0]);
|
||||||
return { error: true, message: error.toString() };
|
throw new BadRequestException(error.message[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async connectToWhatsapp({ instanceName, number = null }: InstanceDto) {
|
public async connectToWhatsapp({ instanceName, number = null }: InstanceDto) {
|
||||||
try {
|
try {
|
||||||
this.logger.verbose(
|
this.logger.verbose('requested connectToWhatsapp from ' + instanceName + ' instance');
|
||||||
'requested connectToWhatsapp from ' + instanceName + ' instance',
|
|
||||||
);
|
|
||||||
|
|
||||||
const instance = this.waMonitor.waInstances[instanceName];
|
const instance = this.waMonitor.waInstances[instanceName];
|
||||||
const state = instance?.connectionStatus?.state;
|
const state = instance?.connectionStatus?.state;
|
||||||
|
|
||||||
this.logger.verbose('state: ' + state);
|
this.logger.verbose('state: ' + state);
|
||||||
|
|
||||||
|
if (!state) {
|
||||||
|
throw new BadRequestException('The "' + instanceName + '" instance does not exist');
|
||||||
|
}
|
||||||
|
|
||||||
if (state == 'open') {
|
if (state == 'open') {
|
||||||
return await this.connectionState({ instanceName });
|
return await this.connectionState({ instanceName });
|
||||||
}
|
}
|
||||||
@@ -290,7 +465,7 @@ export class InstanceController {
|
|||||||
this.logger.verbose('logging out instance: ' + instanceName);
|
this.logger.verbose('logging out instance: ' + instanceName);
|
||||||
this.waMonitor.waInstances[instanceName]?.client?.ws?.close();
|
this.waMonitor.waInstances[instanceName]?.client?.ws?.close();
|
||||||
|
|
||||||
return { error: false, message: 'Instance restarted' };
|
return { status: 'SUCCESS', error: false, response: { message: 'Instance restarted' } };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.error(error);
|
this.logger.error(error);
|
||||||
}
|
}
|
||||||
@@ -321,21 +496,17 @@ export class InstanceController {
|
|||||||
const { instance } = await this.connectionState({ instanceName });
|
const { instance } = await this.connectionState({ instanceName });
|
||||||
|
|
||||||
if (instance.state === 'close') {
|
if (instance.state === 'close') {
|
||||||
throw new BadRequestException(
|
throw new BadRequestException('The "' + instanceName + '" instance is not connected');
|
||||||
'The "' + instanceName + '" instance is not connected',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.logger.verbose('logging out instance: ' + instanceName);
|
this.logger.verbose('logging out instance: ' + instanceName);
|
||||||
await this.waMonitor.waInstances[instanceName]?.client?.logout(
|
await this.waMonitor.waInstances[instanceName]?.client?.logout('Log out instance: ' + instanceName);
|
||||||
'Log out instance: ' + instanceName,
|
|
||||||
);
|
|
||||||
|
|
||||||
this.logger.verbose('close connection instance: ' + instanceName);
|
this.logger.verbose('close connection instance: ' + instanceName);
|
||||||
this.waMonitor.waInstances[instanceName]?.client?.ws?.close();
|
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) {
|
} catch (error) {
|
||||||
throw new InternalServerErrorException(error.toString());
|
throw new InternalServerErrorException(error.toString());
|
||||||
}
|
}
|
||||||
@@ -346,9 +517,7 @@ export class InstanceController {
|
|||||||
const { instance } = await this.connectionState({ instanceName });
|
const { instance } = await this.connectionState({ instanceName });
|
||||||
|
|
||||||
if (instance.state === 'open') {
|
if (instance.state === 'open') {
|
||||||
throw new BadRequestException(
|
throw new BadRequestException('The "' + instanceName + '" instance needs to be disconnected');
|
||||||
'The "' + instanceName + '" instance needs to be disconnected',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (instance.state === 'connecting') {
|
if (instance.state === 'connecting') {
|
||||||
@@ -356,13 +525,13 @@ export class InstanceController {
|
|||||||
|
|
||||||
await this.logout({ instanceName });
|
await this.logout({ instanceName });
|
||||||
delete this.waMonitor.waInstances[instanceName];
|
delete this.waMonitor.waInstances[instanceName];
|
||||||
return { error: false, message: 'Instance deleted' };
|
return { status: 'SUCCESS', error: false, response: { message: 'Instance deleted' } };
|
||||||
} else {
|
} else {
|
||||||
this.logger.verbose('deleting instance: ' + instanceName);
|
this.logger.verbose('deleting instance: ' + instanceName);
|
||||||
|
|
||||||
delete this.waMonitor.waInstances[instanceName];
|
delete this.waMonitor.waInstances[instanceName];
|
||||||
this.eventEmitter.emit('remove.instance', instanceName, 'inner');
|
this.eventEmitter.emit('remove.instance', instanceName, 'inner');
|
||||||
return { error: false, message: 'Instance deleted' };
|
return { status: 'SUCCESS', error: false, response: { message: 'Instance deleted' } };
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new BadRequestException(error.toString());
|
throw new BadRequestException(error.toString());
|
||||||
|
|||||||
26
src/whatsapp/controllers/proxy.controller.ts
Normal file
26
src/whatsapp/controllers/proxy.controller.ts
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
53
src/whatsapp/controllers/rabbitmq.controller.ts
Normal file
53
src/whatsapp/controllers/rabbitmq.controller.ts
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
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',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.rabbitmqService.create(instance, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async findRabbitmq(instance: InstanceDto) {
|
||||||
|
logger.verbose('requested findRabbitmq from ' + instance.instanceName + ' instance');
|
||||||
|
return this.rabbitmqService.find(instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
import { isBase64, isURL } from 'class-validator';
|
import { isBase64, isURL } from 'class-validator';
|
||||||
|
|
||||||
|
import { Logger } from '../../config/logger.config';
|
||||||
import { BadRequestException } from '../../exceptions';
|
import { BadRequestException } from '../../exceptions';
|
||||||
import { InstanceDto } from '../dto/instance.dto';
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
import {
|
import {
|
||||||
@@ -16,8 +18,6 @@ import {
|
|||||||
} from '../dto/sendMessage.dto';
|
} from '../dto/sendMessage.dto';
|
||||||
import { WAMonitoringService } from '../services/monitor.service';
|
import { WAMonitoringService } from '../services/monitor.service';
|
||||||
|
|
||||||
import { Logger } from '../../config/logger.config';
|
|
||||||
|
|
||||||
const logger = new Logger('MessageRouter');
|
const logger = new Logger('MessageRouter');
|
||||||
|
|
||||||
export class SendMessageController {
|
export class SendMessageController {
|
||||||
@@ -39,12 +39,7 @@ export class SendMessageController {
|
|||||||
throw new BadRequestException('For base64 the file name must be informed.');
|
throw new BadRequestException('For base64 the file name must be informed.');
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.verbose(
|
logger.verbose('isURL: ' + isURL(data?.mediaMessage?.media) + ', isBase64: ' + isBase64(data?.mediaMessage?.media));
|
||||||
'isURL: ' +
|
|
||||||
isURL(data?.mediaMessage?.media) +
|
|
||||||
', isBase64: ' +
|
|
||||||
isBase64(data?.mediaMessage?.media),
|
|
||||||
);
|
|
||||||
if (isURL(data?.mediaMessage?.media) || isBase64(data?.mediaMessage?.media)) {
|
if (isURL(data?.mediaMessage?.media) || isBase64(data?.mediaMessage?.media)) {
|
||||||
return await this.waMonitor.waInstances[instanceName].mediaMessage(data);
|
return await this.waMonitor.waInstances[instanceName].mediaMessage(data);
|
||||||
}
|
}
|
||||||
@@ -55,10 +50,7 @@ export class SendMessageController {
|
|||||||
logger.verbose('requested sendSticker from ' + instanceName + ' instance');
|
logger.verbose('requested sendSticker from ' + instanceName + ' instance');
|
||||||
|
|
||||||
logger.verbose(
|
logger.verbose(
|
||||||
'isURL: ' +
|
'isURL: ' + isURL(data?.stickerMessage?.image) + ', isBase64: ' + isBase64(data?.stickerMessage?.image),
|
||||||
isURL(data?.stickerMessage?.image) +
|
|
||||||
', isBase64: ' +
|
|
||||||
isBase64(data?.stickerMessage?.image),
|
|
||||||
);
|
);
|
||||||
if (isURL(data.stickerMessage.image) || isBase64(data.stickerMessage.image)) {
|
if (isURL(data.stickerMessage.image) || isBase64(data.stickerMessage.image)) {
|
||||||
return await this.waMonitor.waInstances[instanceName].mediaSticker(data);
|
return await this.waMonitor.waInstances[instanceName].mediaSticker(data);
|
||||||
@@ -69,12 +61,7 @@ export class SendMessageController {
|
|||||||
public async sendWhatsAppAudio({ instanceName }: InstanceDto, data: SendAudioDto) {
|
public async sendWhatsAppAudio({ instanceName }: InstanceDto, data: SendAudioDto) {
|
||||||
logger.verbose('requested sendWhatsAppAudio from ' + instanceName + ' instance');
|
logger.verbose('requested sendWhatsAppAudio from ' + instanceName + ' instance');
|
||||||
|
|
||||||
logger.verbose(
|
logger.verbose('isURL: ' + isURL(data?.audioMessage?.audio) + ', isBase64: ' + isBase64(data?.audioMessage?.audio));
|
||||||
'isURL: ' +
|
|
||||||
isURL(data?.audioMessage?.audio) +
|
|
||||||
', isBase64: ' +
|
|
||||||
isBase64(data?.audioMessage?.audio),
|
|
||||||
);
|
|
||||||
if (isURL(data.audioMessage.audio) || isBase64(data.audioMessage.audio)) {
|
if (isURL(data.audioMessage.audio) || isBase64(data.audioMessage.audio)) {
|
||||||
return await this.waMonitor.waInstances[instanceName].audioWhatsapp(data);
|
return await this.waMonitor.waInstances[instanceName].audioWhatsapp(data);
|
||||||
}
|
}
|
||||||
@@ -83,10 +70,7 @@ export class SendMessageController {
|
|||||||
|
|
||||||
public async sendButtons({ instanceName }: InstanceDto, data: SendButtonDto) {
|
public async sendButtons({ instanceName }: InstanceDto, data: SendButtonDto) {
|
||||||
logger.verbose('requested sendButtons from ' + instanceName + ' instance');
|
logger.verbose('requested sendButtons from ' + instanceName + ' instance');
|
||||||
if (
|
if (isBase64(data.buttonMessage.mediaMessage?.media) && !data.buttonMessage.mediaMessage?.fileName) {
|
||||||
isBase64(data.buttonMessage.mediaMessage?.media) &&
|
|
||||||
!data.buttonMessage.mediaMessage?.fileName
|
|
||||||
) {
|
|
||||||
throw new BadRequestException('For bse64 the file name must be informed.');
|
throw new BadRequestException('For bse64 the file name must be informed.');
|
||||||
}
|
}
|
||||||
return await this.waMonitor.waInstances[instanceName].buttonMessage(data);
|
return await this.waMonitor.waInstances[instanceName].buttonMessage(data);
|
||||||
@@ -109,7 +93,7 @@ export class SendMessageController {
|
|||||||
|
|
||||||
public async sendReaction({ instanceName }: InstanceDto, data: SendReactionDto) {
|
public async sendReaction({ instanceName }: InstanceDto, data: SendReactionDto) {
|
||||||
logger.verbose('requested sendReaction from ' + instanceName + ' instance');
|
logger.verbose('requested sendReaction from ' + instanceName + ' instance');
|
||||||
if (!data.reactionMessage.reaction.match(/[^\(\)\w\sà-ú"-\+]+/)) {
|
if (!data.reactionMessage.reaction.match(/[^()\w\sà-ú"-+]+/)) {
|
||||||
throw new BadRequestException('"reaction" must be an emoji');
|
throw new BadRequestException('"reaction" must be an emoji');
|
||||||
}
|
}
|
||||||
return await this.waMonitor.waInstances[instanceName].reactionMessage(data);
|
return await this.waMonitor.waInstances[instanceName].reactionMessage(data);
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { isURL } from 'class-validator';
|
// import { isURL } from 'class-validator';
|
||||||
import { BadRequestException } from '../../exceptions';
|
|
||||||
|
import { Logger } from '../../config/logger.config';
|
||||||
|
// import { BadRequestException } from '../../exceptions';
|
||||||
import { InstanceDto } from '../dto/instance.dto';
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
import { SettingsDto } from '../dto/settings.dto';
|
import { SettingsDto } from '../dto/settings.dto';
|
||||||
import { SettingsService } from '../services/settings.service';
|
import { SettingsService } from '../services/settings.service';
|
||||||
import { Logger } from '../../config/logger.config';
|
|
||||||
|
|
||||||
const logger = new Logger('SettingsController');
|
const logger = new Logger('SettingsController');
|
||||||
|
|
||||||
@@ -11,9 +12,7 @@ export class SettingsController {
|
|||||||
constructor(private readonly settingsService: SettingsService) {}
|
constructor(private readonly settingsService: SettingsService) {}
|
||||||
|
|
||||||
public async createSettings(instance: InstanceDto, data: SettingsDto) {
|
public async createSettings(instance: InstanceDto, data: SettingsDto) {
|
||||||
logger.verbose(
|
logger.verbose('requested createSettings from ' + instance.instanceName + ' instance');
|
||||||
'requested createSettings from ' + instance.instanceName + ' instance',
|
|
||||||
);
|
|
||||||
|
|
||||||
return this.settingsService.create(instance, data);
|
return this.settingsService.create(instance, data);
|
||||||
}
|
}
|
||||||
|
|||||||
46
src/whatsapp/controllers/typebot.controller.ts
Normal file
46
src/whatsapp/controllers/typebot.controller.ts
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,26 +1,15 @@
|
|||||||
import { Request, Response } from 'express';
|
import { Request, Response } from 'express';
|
||||||
import { Auth, ConfigService } from '../../config/env.config';
|
|
||||||
import { BadRequestException } from '../../exceptions';
|
import { ConfigService } from '../../config/env.config';
|
||||||
import { InstanceDto } from '../dto/instance.dto';
|
|
||||||
import { HttpStatus } from '../routers/index.router';
|
import { HttpStatus } from '../routers/index.router';
|
||||||
import { WAMonitoringService } from '../services/monitor.service';
|
import { WAMonitoringService } from '../services/monitor.service';
|
||||||
|
|
||||||
export class ViewsController {
|
export class ViewsController {
|
||||||
constructor(
|
constructor(private readonly waMonit: WAMonitoringService, private readonly configService: ConfigService) {}
|
||||||
private readonly waMonit: WAMonitoringService,
|
|
||||||
private readonly configService: ConfigService,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
public async qrcode(request: Request, response: Response) {
|
public async manager(request: Request, response: Response) {
|
||||||
try {
|
try {
|
||||||
const param = request.params as unknown as InstanceDto;
|
return response.status(HttpStatus.OK).render('manager');
|
||||||
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) {
|
} catch (error) {
|
||||||
console.log('ERROR: ', error);
|
console.log('ERROR: ', error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { isURL } from 'class-validator';
|
import { isURL } from 'class-validator';
|
||||||
|
|
||||||
|
import { Logger } from '../../config/logger.config';
|
||||||
import { BadRequestException } from '../../exceptions';
|
import { BadRequestException } from '../../exceptions';
|
||||||
import { InstanceDto } from '../dto/instance.dto';
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
import { WebhookDto } from '../dto/webhook.dto';
|
import { WebhookDto } from '../dto/webhook.dto';
|
||||||
import { WebhookService } from '../services/webhook.service';
|
import { WebhookService } from '../services/webhook.service';
|
||||||
import { Logger } from '../../config/logger.config';
|
|
||||||
|
|
||||||
const logger = new Logger('WebhookController');
|
const logger = new Logger('WebhookController');
|
||||||
|
|
||||||
@@ -13,14 +14,41 @@ export class WebhookController {
|
|||||||
public async createWebhook(instance: InstanceDto, data: WebhookDto) {
|
public async createWebhook(instance: InstanceDto, data: WebhookDto) {
|
||||||
logger.verbose('requested createWebhook from ' + instance.instanceName + ' instance');
|
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');
|
throw new BadRequestException('Invalid "url" property');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data.enabled = data.enabled ?? true;
|
||||||
|
|
||||||
if (!data.enabled) {
|
if (!data.enabled) {
|
||||||
logger.verbose('webhook disabled');
|
logger.verbose('webhook disabled');
|
||||||
data.url = '';
|
data.url = '';
|
||||||
data.events = [];
|
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',
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.webhookService.create(instance, data);
|
return this.webhookService.create(instance, data);
|
||||||
|
|||||||
53
src/whatsapp/controllers/websocket.controller.ts
Normal file
53
src/whatsapp/controllers/websocket.controller.ts
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
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',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.websocketService.create(instance, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async findWebsocket(instance: InstanceDto) {
|
||||||
|
logger.verbose('requested findWebsocket from ' + instance.instanceName + ' instance');
|
||||||
|
return this.websocketService.find(instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,16 +1,7 @@
|
|||||||
import {
|
import { proto, WAPrivacyOnlineValue, WAPrivacyValue, WAReadReceiptsValue } from '@whiskeysockets/baileys';
|
||||||
WAPrivacyOnlineValue,
|
|
||||||
WAPrivacyValue,
|
|
||||||
WAReadReceiptsValue,
|
|
||||||
proto,
|
|
||||||
} from '@whiskeysockets/baileys';
|
|
||||||
|
|
||||||
export class OnWhatsAppDto {
|
export class OnWhatsAppDto {
|
||||||
constructor(
|
constructor(public readonly jid: string, public readonly exists: boolean, public readonly name?: string) {}
|
||||||
public readonly jid: string,
|
|
||||||
public readonly exists: boolean,
|
|
||||||
public readonly name?: string,
|
|
||||||
) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class getBase64FromMediaMessageDto {
|
export class getBase64FromMediaMessageDto {
|
||||||
@@ -62,13 +53,14 @@ export class ReadMessageDto {
|
|||||||
read_messages: Key[];
|
read_messages: Key[];
|
||||||
}
|
}
|
||||||
|
|
||||||
class LastMessage {
|
export class LastMessage {
|
||||||
key: Key;
|
key: Key;
|
||||||
messageTimestamp?: number;
|
messageTimestamp?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ArchiveChatDto {
|
export class ArchiveChatDto {
|
||||||
lastMessage: LastMessage;
|
lastMessage?: LastMessage;
|
||||||
|
chat?: string;
|
||||||
archive: boolean;
|
archive: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,4 +18,16 @@ export class InstanceDto {
|
|||||||
chatwoot_sign_msg?: boolean;
|
chatwoot_sign_msg?: boolean;
|
||||||
chatwoot_reopen_conversation?: boolean;
|
chatwoot_reopen_conversation?: boolean;
|
||||||
chatwoot_conversation_pending?: boolean;
|
chatwoot_conversation_pending?: boolean;
|
||||||
|
websocket_enabled?: boolean;
|
||||||
|
websocket_events?: string[];
|
||||||
|
rabbitmq_enabled?: boolean;
|
||||||
|
rabbitmq_events?: string[];
|
||||||
|
typebot_url?: string;
|
||||||
|
typebot?: string;
|
||||||
|
typebot_expire?: number;
|
||||||
|
typebot_keyword_finish?: string;
|
||||||
|
typebot_delay_message?: number;
|
||||||
|
typebot_unknown_message?: string;
|
||||||
|
proxy_enabled?: boolean;
|
||||||
|
proxy_proxy?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
4
src/whatsapp/dto/proxy.dto.ts
Normal file
4
src/whatsapp/dto/proxy.dto.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export class ProxyDto {
|
||||||
|
enabled: boolean;
|
||||||
|
proxy: string;
|
||||||
|
}
|
||||||
4
src/whatsapp/dto/rabbitmq.dto.ts
Normal file
4
src/whatsapp/dto/rabbitmq.dto.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export class RabbitmqDto {
|
||||||
|
enabled: boolean;
|
||||||
|
events?: string[];
|
||||||
|
}
|
||||||
18
src/whatsapp/dto/typebot.dto.ts
Normal file
18
src/whatsapp/dto/typebot.dto.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
export class Session {
|
||||||
|
remoteJid?: string;
|
||||||
|
sessionId?: string;
|
||||||
|
status?: string;
|
||||||
|
createdAt?: number;
|
||||||
|
updateAt?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TypebotDto {
|
||||||
|
enabled?: boolean;
|
||||||
|
url: string;
|
||||||
|
typebot?: string;
|
||||||
|
expire?: number;
|
||||||
|
keyword_finish?: string;
|
||||||
|
delay_message?: number;
|
||||||
|
unknown_message?: string;
|
||||||
|
sessions?: Session[];
|
||||||
|
}
|
||||||
4
src/whatsapp/dto/websocket.dto.ts
Normal file
4
src/whatsapp/dto/websocket.dto.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export class WebsocketDto {
|
||||||
|
enabled: boolean;
|
||||||
|
events?: string[];
|
||||||
|
}
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
import { isJWT } from 'class-validator';
|
import { isJWT } from 'class-validator';
|
||||||
import { NextFunction, Request, Response } from 'express';
|
import { NextFunction, Request, Response } from 'express';
|
||||||
import jwt from 'jsonwebtoken';
|
import jwt from 'jsonwebtoken';
|
||||||
|
|
||||||
|
import { name } from '../../../package.json';
|
||||||
import { Auth, configService } from '../../config/env.config';
|
import { Auth, configService } from '../../config/env.config';
|
||||||
import { Logger } from '../../config/logger.config';
|
import { Logger } from '../../config/logger.config';
|
||||||
import { name } from '../../../package.json';
|
import { ForbiddenException, UnauthorizedException } from '../../exceptions';
|
||||||
import { InstanceDto } from '../dto/instance.dto';
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
import { JwtPayload } from '../services/auth.service';
|
import { JwtPayload } from '../services/auth.service';
|
||||||
import { ForbiddenException, UnauthorizedException } from '../../exceptions';
|
|
||||||
import { repository } from '../whatsapp.module';
|
import { repository } from '../whatsapp.module';
|
||||||
|
|
||||||
const logger = new Logger('GUARD');
|
const logger = new Logger('GUARD');
|
||||||
@@ -22,15 +23,8 @@ async function jwtGuard(req: Request, res: Response, next: NextFunction) {
|
|||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if ((req.originalUrl.includes('/instance/create') || req.originalUrl.includes('/instance/fetchInstances')) && !key) {
|
||||||
(req.originalUrl.includes('/instance/create') ||
|
throw new ForbiddenException('Missing global api key', 'The global api key must be set');
|
||||||
req.originalUrl.includes('/instance/fetchInstances')) &&
|
|
||||||
!key
|
|
||||||
) {
|
|
||||||
throw new ForbiddenException(
|
|
||||||
'Missing global api key',
|
|
||||||
'The global api key must be set',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const jwtOpts = configService.get<Auth>('AUTHENTICATION').JWT;
|
const jwtOpts = configService.get<Auth>('AUTHENTICATION').JWT;
|
||||||
@@ -69,15 +63,8 @@ async function apikey(req: Request, res: Response, next: NextFunction) {
|
|||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if ((req.originalUrl.includes('/instance/create') || req.originalUrl.includes('/instance/fetchInstances')) && !key) {
|
||||||
(req.originalUrl.includes('/instance/create') ||
|
throw new ForbiddenException('Missing global api key', 'The global api key must be set');
|
||||||
req.originalUrl.includes('/instance/fetchInstances')) &&
|
|
||||||
!key
|
|
||||||
) {
|
|
||||||
throw new ForbiddenException(
|
|
||||||
'Missing global api key',
|
|
||||||
'The global api key must be set',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -86,7 +73,9 @@ async function apikey(req: Request, res: Response, next: NextFunction) {
|
|||||||
if (instanceKey.apikey === key) {
|
if (instanceKey.apikey === key) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
} catch (error) {}
|
} catch (error) {
|
||||||
|
logger.error(error);
|
||||||
|
}
|
||||||
|
|
||||||
throw new UnauthorizedException();
|
throw new UnauthorizedException();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,13 @@
|
|||||||
import { NextFunction, Request, Response } from 'express';
|
import { NextFunction, Request, Response } from 'express';
|
||||||
import { existsSync } from 'fs';
|
import { existsSync } from 'fs';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
|
||||||
|
import { configService, Database, Redis } from '../../config/env.config';
|
||||||
import { INSTANCE_DIR } from '../../config/path.config';
|
import { INSTANCE_DIR } from '../../config/path.config';
|
||||||
import { dbserver } from '../../db/db.connect';
|
import { BadRequestException, ForbiddenException, NotFoundException } from '../../exceptions';
|
||||||
import {
|
import { dbserver } from '../../libs/db.connect';
|
||||||
BadRequestException,
|
|
||||||
ForbiddenException,
|
|
||||||
NotFoundException,
|
|
||||||
} from '../../exceptions';
|
|
||||||
import { InstanceDto } from '../dto/instance.dto';
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
import { cache, waMonitor } from '../whatsapp.module';
|
import { cache, waMonitor } from '../whatsapp.module';
|
||||||
import { Database, Redis, configService } from '../../config/env.config';
|
|
||||||
|
|
||||||
async function getInstance(instanceName: string) {
|
async function getInstance(instanceName: string) {
|
||||||
const db = configService.get<Database>('DATABASE');
|
const db = configService.get<Database>('DATABASE');
|
||||||
@@ -35,10 +32,7 @@ async function getInstance(instanceName: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function instanceExistsGuard(req: Request, _: Response, next: NextFunction) {
|
export async function instanceExistsGuard(req: Request, _: Response, next: NextFunction) {
|
||||||
if (
|
if (req.originalUrl.includes('/instance/create') || req.originalUrl.includes('/instance/fetchInstances')) {
|
||||||
req.originalUrl.includes('/instance/create') ||
|
|
||||||
req.originalUrl.includes('/instance/fetchInstances')
|
|
||||||
) {
|
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,9 +52,7 @@ export async function instanceLoggedGuard(req: Request, _: Response, next: NextF
|
|||||||
if (req.originalUrl.includes('/instance/create')) {
|
if (req.originalUrl.includes('/instance/create')) {
|
||||||
const instance = req.body as InstanceDto;
|
const instance = req.body as InstanceDto;
|
||||||
if (await getInstance(instance.instanceName)) {
|
if (await getInstance(instance.instanceName)) {
|
||||||
throw new ForbiddenException(
|
throw new ForbiddenException(`This name "${instance.instanceName}" is already in use.`);
|
||||||
`This name "${instance.instanceName}" is already in use.`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (waMonitor.waInstances[instance.instanceName]) {
|
if (waMonitor.waInstances[instance.instanceName]) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Schema } from 'mongoose';
|
import { Schema } from 'mongoose';
|
||||||
import { dbserver } from '../../db/db.connect';
|
|
||||||
|
import { dbserver } from '../../libs/db.connect';
|
||||||
|
|
||||||
export class AuthRaw {
|
export class AuthRaw {
|
||||||
_id?: string;
|
_id?: string;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Schema } from 'mongoose';
|
import { Schema } from 'mongoose';
|
||||||
import { dbserver } from '../../db/db.connect';
|
|
||||||
|
import { dbserver } from '../../libs/db.connect';
|
||||||
|
|
||||||
export class ChatRaw {
|
export class ChatRaw {
|
||||||
_id?: string;
|
_id?: string;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Schema } from 'mongoose';
|
import { Schema } from 'mongoose';
|
||||||
import { dbserver } from '../../db/db.connect';
|
|
||||||
|
import { dbserver } from '../../libs/db.connect';
|
||||||
|
|
||||||
export class ChatwootRaw {
|
export class ChatwootRaw {
|
||||||
_id?: string;
|
_id?: string;
|
||||||
@@ -25,9 +26,5 @@ const chatwootSchema = new Schema<ChatwootRaw>({
|
|||||||
number: { type: String, required: true },
|
number: { type: String, required: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
export const ChatwootModel = dbserver?.model(
|
export const ChatwootModel = dbserver?.model(ChatwootRaw.name, chatwootSchema, 'chatwoot');
|
||||||
ChatwootRaw.name,
|
|
||||||
chatwootSchema,
|
|
||||||
'chatwoot',
|
|
||||||
);
|
|
||||||
export type IChatwootModel = typeof ChatwootModel;
|
export type IChatwootModel = typeof ChatwootModel;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Schema } from 'mongoose';
|
import { Schema } from 'mongoose';
|
||||||
import { dbserver } from '../../db/db.connect';
|
|
||||||
|
import { dbserver } from '../../libs/db.connect';
|
||||||
|
|
||||||
export class ContactRaw {
|
export class ContactRaw {
|
||||||
_id?: string;
|
_id?: string;
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
|
export * from './auth.model';
|
||||||
export * from './chat.model';
|
export * from './chat.model';
|
||||||
|
export * from './chatwoot.model';
|
||||||
export * from './contact.model';
|
export * from './contact.model';
|
||||||
export * from './message.model';
|
export * from './message.model';
|
||||||
export * from './auth.model';
|
export * from './proxy.model';
|
||||||
export * from './webhook.model';
|
export * from './rabbitmq.model';
|
||||||
export * from './chatwoot.model';
|
|
||||||
export * from './settings.model';
|
export * from './settings.model';
|
||||||
|
export * from './typebot.model';
|
||||||
|
export * from './webhook.model';
|
||||||
|
export * from './websocket.model';
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Schema } from 'mongoose';
|
import { Schema } from 'mongoose';
|
||||||
import { dbserver } from '../../db/db.connect';
|
|
||||||
|
import { dbserver } from '../../libs/db.connect';
|
||||||
import { wa } from '../types/wa.types';
|
import { wa } from '../types/wa.types';
|
||||||
|
|
||||||
class Key {
|
class Key {
|
||||||
@@ -64,9 +65,5 @@ const messageUpdateSchema = new Schema<MessageUpdateRaw>({
|
|||||||
owner: { type: String, required: true, min: 1 },
|
owner: { type: String, required: true, min: 1 },
|
||||||
});
|
});
|
||||||
|
|
||||||
export const MessageUpModel = dbserver?.model(
|
export const MessageUpModel = dbserver?.model(MessageUpdateRaw.name, messageUpdateSchema, 'messageUpdate');
|
||||||
MessageUpdateRaw.name,
|
|
||||||
messageUpdateSchema,
|
|
||||||
'messageUpdate',
|
|
||||||
);
|
|
||||||
export type IMessageUpModel = typeof MessageUpModel;
|
export type IMessageUpModel = typeof MessageUpModel;
|
||||||
|
|||||||
18
src/whatsapp/models/proxy.model.ts
Normal file
18
src/whatsapp/models/proxy.model.ts
Normal 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;
|
||||||
18
src/whatsapp/models/rabbitmq.model.ts
Normal file
18
src/whatsapp/models/rabbitmq.model.ts
Normal 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;
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Schema } from 'mongoose';
|
import { Schema } from 'mongoose';
|
||||||
import { dbserver } from '../../db/db.connect';
|
|
||||||
|
import { dbserver } from '../../libs/db.connect';
|
||||||
|
|
||||||
export class SettingsRaw {
|
export class SettingsRaw {
|
||||||
_id?: string;
|
_id?: string;
|
||||||
@@ -21,9 +22,5 @@ const settingsSchema = new Schema<SettingsRaw>({
|
|||||||
read_status: { type: Boolean, required: true },
|
read_status: { type: Boolean, required: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
export const SettingsModel = dbserver?.model(
|
export const SettingsModel = dbserver?.model(SettingsRaw.name, settingsSchema, 'settings');
|
||||||
SettingsRaw.name,
|
|
||||||
settingsSchema,
|
|
||||||
'settings',
|
|
||||||
);
|
|
||||||
export type ISettingsModel = typeof SettingsModel;
|
export type ISettingsModel = typeof SettingsModel;
|
||||||
|
|||||||
46
src/whatsapp/models/typebot.model.ts
Normal file
46
src/whatsapp/models/typebot.model.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import { Schema } from 'mongoose';
|
||||||
|
|
||||||
|
import { dbserver } from '../../libs/db.connect';
|
||||||
|
|
||||||
|
class Session {
|
||||||
|
remoteJid?: string;
|
||||||
|
sessionId?: string;
|
||||||
|
status?: string;
|
||||||
|
createdAt?: number;
|
||||||
|
updateAt?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TypebotRaw {
|
||||||
|
_id?: string;
|
||||||
|
enabled?: boolean;
|
||||||
|
url: string;
|
||||||
|
typebot?: string;
|
||||||
|
expire?: number;
|
||||||
|
keyword_finish?: string;
|
||||||
|
delay_message?: number;
|
||||||
|
unknown_message?: string;
|
||||||
|
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 },
|
||||||
|
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 },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
export const TypebotModel = dbserver?.model(TypebotRaw.name, typebotSchema, 'typebot');
|
||||||
|
export type ITypebotModel = typeof TypebotModel;
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Schema } from 'mongoose';
|
import { Schema } from 'mongoose';
|
||||||
import { dbserver } from '../../db/db.connect';
|
|
||||||
|
import { dbserver } from '../../libs/db.connect';
|
||||||
|
|
||||||
export class WebhookRaw {
|
export class WebhookRaw {
|
||||||
_id?: string;
|
_id?: string;
|
||||||
|
|||||||
18
src/whatsapp/models/websocket.model.ts
Normal file
18
src/whatsapp/models/websocket.model.ts
Normal 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;
|
||||||
@@ -1,16 +1,14 @@
|
|||||||
import { join } from 'path';
|
|
||||||
import { Auth, ConfigService, Database } from '../../config/env.config';
|
|
||||||
import { IInsert, Repository } from '../abstract/abstract.repository';
|
|
||||||
import { IAuthModel, AuthRaw } from '../models';
|
|
||||||
import { readFileSync } from 'fs';
|
import { readFileSync } from 'fs';
|
||||||
import { AUTH_DIR } from '../../config/path.config';
|
import { join } from 'path';
|
||||||
|
|
||||||
|
import { Auth, ConfigService } from '../../config/env.config';
|
||||||
import { Logger } from '../../config/logger.config';
|
import { Logger } from '../../config/logger.config';
|
||||||
|
import { AUTH_DIR } from '../../config/path.config';
|
||||||
|
import { IInsert, Repository } from '../abstract/abstract.repository';
|
||||||
|
import { AuthRaw, IAuthModel } from '../models';
|
||||||
|
|
||||||
export class AuthRepository extends Repository {
|
export class AuthRepository extends Repository {
|
||||||
constructor(
|
constructor(private readonly authModel: IAuthModel, readonly configService: ConfigService) {
|
||||||
private readonly authModel: IAuthModel,
|
|
||||||
readonly configService: ConfigService,
|
|
||||||
) {
|
|
||||||
super(configService);
|
super(configService);
|
||||||
this.auth = configService.get<Auth>('AUTHENTICATION');
|
this.auth = configService.get<Auth>('AUTHENTICATION');
|
||||||
}
|
}
|
||||||
@@ -23,11 +21,7 @@ export class AuthRepository extends Repository {
|
|||||||
this.logger.verbose('creating auth');
|
this.logger.verbose('creating auth');
|
||||||
if (this.dbSettings.ENABLED) {
|
if (this.dbSettings.ENABLED) {
|
||||||
this.logger.verbose('saving auth to db');
|
this.logger.verbose('saving auth to db');
|
||||||
const insert = await this.authModel.replaceOne(
|
const insert = await this.authModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
|
||||||
{ _id: instance },
|
|
||||||
{ ...data },
|
|
||||||
{ upsert: true },
|
|
||||||
);
|
|
||||||
|
|
||||||
this.logger.verbose('auth saved to db: ' + insert.modifiedCount + ' auth');
|
this.logger.verbose('auth saved to db: ' + insert.modifiedCount + ' auth');
|
||||||
return { insertCount: insert.modifiedCount };
|
return { insertCount: insert.modifiedCount };
|
||||||
@@ -40,9 +34,7 @@ export class AuthRepository extends Repository {
|
|||||||
fileName: instance,
|
fileName: instance,
|
||||||
data,
|
data,
|
||||||
});
|
});
|
||||||
this.logger.verbose(
|
this.logger.verbose('auth saved to store in path: ' + join(AUTH_DIR, this.auth.TYPE) + '/' + instance);
|
||||||
'auth saved to store in path: ' + join(AUTH_DIR, this.auth.TYPE) + '/' + instance,
|
|
||||||
);
|
|
||||||
|
|
||||||
this.logger.verbose('auth created');
|
this.logger.verbose('auth created');
|
||||||
return { insertCount: 1 };
|
return { insertCount: 1 };
|
||||||
|
|||||||
@@ -1,29 +1,23 @@
|
|||||||
import { join } from 'path';
|
|
||||||
import { ConfigService, StoreConf } from '../../config/env.config';
|
|
||||||
import { IInsert, Repository } from '../abstract/abstract.repository';
|
|
||||||
import { opendirSync, readFileSync, rmSync } from 'fs';
|
import { opendirSync, readFileSync, rmSync } from 'fs';
|
||||||
import { ChatRaw, IChatModel } from '../models';
|
import { join } from 'path';
|
||||||
|
|
||||||
|
import { ConfigService, StoreConf } from '../../config/env.config';
|
||||||
import { Logger } from '../../config/logger.config';
|
import { Logger } from '../../config/logger.config';
|
||||||
|
import { IInsert, Repository } from '../abstract/abstract.repository';
|
||||||
|
import { ChatRaw, IChatModel } from '../models';
|
||||||
|
|
||||||
export class ChatQuery {
|
export class ChatQuery {
|
||||||
where: ChatRaw;
|
where: ChatRaw;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ChatRepository extends Repository {
|
export class ChatRepository extends Repository {
|
||||||
constructor(
|
constructor(private readonly chatModel: IChatModel, private readonly configService: ConfigService) {
|
||||||
private readonly chatModel: IChatModel,
|
|
||||||
private readonly configService: ConfigService,
|
|
||||||
) {
|
|
||||||
super(configService);
|
super(configService);
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly logger = new Logger('ChatRepository');
|
private readonly logger = new Logger('ChatRepository');
|
||||||
|
|
||||||
public async insert(
|
public async insert(data: ChatRaw[], instanceName: string, saveDb = false): Promise<IInsert> {
|
||||||
data: ChatRaw[],
|
|
||||||
instanceName: string,
|
|
||||||
saveDb = false,
|
|
||||||
): Promise<IInsert> {
|
|
||||||
this.logger.verbose('inserting chats');
|
this.logger.verbose('inserting chats');
|
||||||
if (data.length === 0) {
|
if (data.length === 0) {
|
||||||
this.logger.verbose('no chats to insert');
|
this.logger.verbose('no chats to insert');
|
||||||
@@ -53,10 +47,7 @@ export class ChatRepository extends Repository {
|
|||||||
data: chat,
|
data: chat,
|
||||||
});
|
});
|
||||||
this.logger.verbose(
|
this.logger.verbose(
|
||||||
'chats saved to store in path: ' +
|
'chats saved to store in path: ' + join(this.storePath, 'chats', instanceName) + '/' + chat.id,
|
||||||
join(this.storePath, 'chats', instanceName) +
|
|
||||||
'/' +
|
|
||||||
chat.id,
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -89,10 +80,9 @@ export class ChatRepository extends Repository {
|
|||||||
if (dirent.isFile()) {
|
if (dirent.isFile()) {
|
||||||
chats.push(
|
chats.push(
|
||||||
JSON.parse(
|
JSON.parse(
|
||||||
readFileSync(
|
readFileSync(join(this.storePath, 'chats', query.where.owner, dirent.name), {
|
||||||
join(this.storePath, 'chats', query.where.owner, dirent.name),
|
encoding: 'utf-8',
|
||||||
{ encoding: 'utf-8' },
|
}),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
import { IInsert, Repository } from '../abstract/abstract.repository';
|
|
||||||
import { ConfigService } from '../../config/env.config';
|
|
||||||
import { join } from 'path';
|
|
||||||
import { readFileSync } from 'fs';
|
import { readFileSync } from 'fs';
|
||||||
import { IChatwootModel, ChatwootRaw } from '../models';
|
import { join } from 'path';
|
||||||
|
|
||||||
|
import { ConfigService } from '../../config/env.config';
|
||||||
import { Logger } from '../../config/logger.config';
|
import { Logger } from '../../config/logger.config';
|
||||||
|
import { IInsert, Repository } from '../abstract/abstract.repository';
|
||||||
|
import { ChatwootRaw, IChatwootModel } from '../models';
|
||||||
|
|
||||||
export class ChatwootRepository extends Repository {
|
export class ChatwootRepository extends Repository {
|
||||||
constructor(
|
constructor(private readonly chatwootModel: IChatwootModel, private readonly configService: ConfigService) {
|
||||||
private readonly chatwootModel: IChatwootModel,
|
|
||||||
private readonly configService: ConfigService,
|
|
||||||
) {
|
|
||||||
super(configService);
|
super(configService);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,15 +18,9 @@ export class ChatwootRepository extends Repository {
|
|||||||
this.logger.verbose('creating chatwoot');
|
this.logger.verbose('creating chatwoot');
|
||||||
if (this.dbSettings.ENABLED) {
|
if (this.dbSettings.ENABLED) {
|
||||||
this.logger.verbose('saving chatwoot to db');
|
this.logger.verbose('saving chatwoot to db');
|
||||||
const insert = await this.chatwootModel.replaceOne(
|
const insert = await this.chatwootModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
|
||||||
{ _id: instance },
|
|
||||||
{ ...data },
|
|
||||||
{ upsert: true },
|
|
||||||
);
|
|
||||||
|
|
||||||
this.logger.verbose(
|
this.logger.verbose('chatwoot saved to db: ' + insert.modifiedCount + ' chatwoot');
|
||||||
'chatwoot saved to db: ' + insert.modifiedCount + ' chatwoot',
|
|
||||||
);
|
|
||||||
return { insertCount: insert.modifiedCount };
|
return { insertCount: insert.modifiedCount };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,12 +32,7 @@ export class ChatwootRepository extends Repository {
|
|||||||
data,
|
data,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.logger.verbose(
|
this.logger.verbose('chatwoot saved to store in path: ' + join(this.storePath, 'chatwoot') + '/' + instance);
|
||||||
'chatwoot saved to store in path: ' +
|
|
||||||
join(this.storePath, 'chatwoot') +
|
|
||||||
'/' +
|
|
||||||
instance,
|
|
||||||
);
|
|
||||||
|
|
||||||
this.logger.verbose('chatwoot created');
|
this.logger.verbose('chatwoot created');
|
||||||
return { insertCount: 1 };
|
return { insertCount: 1 };
|
||||||
|
|||||||
@@ -1,29 +1,23 @@
|
|||||||
import { opendirSync, readFileSync } from 'fs';
|
import { opendirSync, readFileSync } from 'fs';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
|
||||||
import { ConfigService, StoreConf } from '../../config/env.config';
|
import { ConfigService, StoreConf } from '../../config/env.config';
|
||||||
import { ContactRaw, IContactModel } from '../models';
|
|
||||||
import { IInsert, Repository } from '../abstract/abstract.repository';
|
|
||||||
import { Logger } from '../../config/logger.config';
|
import { Logger } from '../../config/logger.config';
|
||||||
|
import { IInsert, Repository } from '../abstract/abstract.repository';
|
||||||
|
import { ContactRaw, IContactModel } from '../models';
|
||||||
|
|
||||||
export class ContactQuery {
|
export class ContactQuery {
|
||||||
where: ContactRaw;
|
where: ContactRaw;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ContactRepository extends Repository {
|
export class ContactRepository extends Repository {
|
||||||
constructor(
|
constructor(private readonly contactModel: IContactModel, private readonly configService: ConfigService) {
|
||||||
private readonly contactModel: IContactModel,
|
|
||||||
private readonly configService: ConfigService,
|
|
||||||
) {
|
|
||||||
super(configService);
|
super(configService);
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly logger = new Logger('ContactRepository');
|
private readonly logger = new Logger('ContactRepository');
|
||||||
|
|
||||||
public async insert(
|
public async insert(data: ContactRaw[], instanceName: string, saveDb = false): Promise<IInsert> {
|
||||||
data: ContactRaw[],
|
|
||||||
instanceName: string,
|
|
||||||
saveDb = false,
|
|
||||||
): Promise<IInsert> {
|
|
||||||
this.logger.verbose('inserting contacts');
|
this.logger.verbose('inserting contacts');
|
||||||
|
|
||||||
if (data.length === 0) {
|
if (data.length === 0) {
|
||||||
@@ -54,10 +48,7 @@ export class ContactRepository extends Repository {
|
|||||||
data: contact,
|
data: contact,
|
||||||
});
|
});
|
||||||
this.logger.verbose(
|
this.logger.verbose(
|
||||||
'contacts saved to store in path: ' +
|
'contacts saved to store in path: ' + join(this.storePath, 'contacts', instanceName) + '/' + contact.id,
|
||||||
join(this.storePath, 'contacts', instanceName) +
|
|
||||||
'/' +
|
|
||||||
contact.id,
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -74,11 +65,7 @@ export class ContactRepository extends Repository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async update(
|
public async update(data: ContactRaw[], instanceName: string, saveDb = false): Promise<IInsert> {
|
||||||
data: ContactRaw[],
|
|
||||||
instanceName: string,
|
|
||||||
saveDb = false,
|
|
||||||
): Promise<IInsert> {
|
|
||||||
try {
|
try {
|
||||||
this.logger.verbose('updating contacts');
|
this.logger.verbose('updating contacts');
|
||||||
|
|
||||||
@@ -119,10 +106,7 @@ export class ContactRepository extends Repository {
|
|||||||
data: contact,
|
data: contact,
|
||||||
});
|
});
|
||||||
this.logger.verbose(
|
this.logger.verbose(
|
||||||
'contacts updated in store in path: ' +
|
'contacts updated in store in path: ' + join(this.storePath, 'contacts', instanceName) + '/' + contact.id,
|
||||||
join(this.storePath, 'contacts', instanceName) +
|
|
||||||
'/' +
|
|
||||||
contact.id,
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -154,15 +138,9 @@ export class ContactRepository extends Repository {
|
|||||||
this.logger.verbose('finding contacts in store by id');
|
this.logger.verbose('finding contacts in store by id');
|
||||||
contacts.push(
|
contacts.push(
|
||||||
JSON.parse(
|
JSON.parse(
|
||||||
readFileSync(
|
readFileSync(join(this.storePath, 'contacts', query.where.owner, query.where.id + '.json'), {
|
||||||
join(
|
encoding: 'utf-8',
|
||||||
this.storePath,
|
}),
|
||||||
'contacts',
|
|
||||||
query.where.owner,
|
|
||||||
query.where.id + '.json',
|
|
||||||
),
|
|
||||||
{ encoding: 'utf-8' },
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@@ -175,10 +153,9 @@ export class ContactRepository extends Repository {
|
|||||||
if (dirent.isFile()) {
|
if (dirent.isFile()) {
|
||||||
contacts.push(
|
contacts.push(
|
||||||
JSON.parse(
|
JSON.parse(
|
||||||
readFileSync(
|
readFileSync(join(this.storePath, 'contacts', query.where.owner, dirent.name), {
|
||||||
join(this.storePath, 'contacts', query.where.owner, dirent.name),
|
encoding: 'utf-8',
|
||||||
{ encoding: 'utf-8' },
|
}),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { ConfigService, StoreConf } from '../../config/env.config';
|
|
||||||
import { join } from 'path';
|
|
||||||
import { IMessageModel, MessageRaw } from '../models';
|
|
||||||
import { IInsert, Repository } from '../abstract/abstract.repository';
|
|
||||||
import { opendirSync, readFileSync } from 'fs';
|
import { opendirSync, readFileSync } from 'fs';
|
||||||
|
import { join } from 'path';
|
||||||
|
|
||||||
|
import { ConfigService, StoreConf } from '../../config/env.config';
|
||||||
import { Logger } from '../../config/logger.config';
|
import { Logger } from '../../config/logger.config';
|
||||||
|
import { IInsert, Repository } from '../abstract/abstract.repository';
|
||||||
|
import { IMessageModel, MessageRaw } from '../models';
|
||||||
|
|
||||||
export class MessageQuery {
|
export class MessageQuery {
|
||||||
where: MessageRaw;
|
where: MessageRaw;
|
||||||
@@ -11,20 +12,13 @@ export class MessageQuery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class MessageRepository extends Repository {
|
export class MessageRepository extends Repository {
|
||||||
constructor(
|
constructor(private readonly messageModel: IMessageModel, private readonly configService: ConfigService) {
|
||||||
private readonly messageModel: IMessageModel,
|
|
||||||
private readonly configService: ConfigService,
|
|
||||||
) {
|
|
||||||
super(configService);
|
super(configService);
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly logger = new Logger('MessageRepository');
|
private readonly logger = new Logger('MessageRepository');
|
||||||
|
|
||||||
public async insert(
|
public async insert(data: MessageRaw[], instanceName: string, saveDb = false): Promise<IInsert> {
|
||||||
data: MessageRaw[],
|
|
||||||
instanceName: string,
|
|
||||||
saveDb = false,
|
|
||||||
): Promise<IInsert> {
|
|
||||||
this.logger.verbose('inserting messages');
|
this.logger.verbose('inserting messages');
|
||||||
|
|
||||||
if (!Array.isArray(data) || data.length === 0) {
|
if (!Array.isArray(data) || data.length === 0) {
|
||||||
@@ -74,10 +68,7 @@ export class MessageRepository extends Repository {
|
|||||||
data: message,
|
data: message,
|
||||||
});
|
});
|
||||||
this.logger.verbose(
|
this.logger.verbose(
|
||||||
'messages saved to store in path: ' +
|
'messages saved to store in path: ' + join(this.storePath, 'messages', instanceName) + '/' + message.key.id,
|
||||||
join(this.storePath, 'messages', instanceName) +
|
|
||||||
'/' +
|
|
||||||
message.key.id,
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -119,15 +110,9 @@ export class MessageRepository extends Repository {
|
|||||||
this.logger.verbose('finding messages in store by id');
|
this.logger.verbose('finding messages in store by id');
|
||||||
messages.push(
|
messages.push(
|
||||||
JSON.parse(
|
JSON.parse(
|
||||||
readFileSync(
|
readFileSync(join(this.storePath, 'messages', query.where.owner, query.where.key.id + '.json'), {
|
||||||
join(
|
encoding: 'utf-8',
|
||||||
this.storePath,
|
}),
|
||||||
'messages',
|
|
||||||
query.where.owner,
|
|
||||||
query.where.key.id + '.json',
|
|
||||||
),
|
|
||||||
{ encoding: 'utf-8' },
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@@ -140,10 +125,9 @@ export class MessageRepository extends Repository {
|
|||||||
if (dirent.isFile()) {
|
if (dirent.isFile()) {
|
||||||
messages.push(
|
messages.push(
|
||||||
JSON.parse(
|
JSON.parse(
|
||||||
readFileSync(
|
readFileSync(join(this.storePath, 'messages', query.where.owner, dirent.name), {
|
||||||
join(this.storePath, 'messages', query.where.owner, dirent.name),
|
encoding: 'utf-8',
|
||||||
{ encoding: 'utf-8' },
|
}),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { ConfigService, StoreConf } from '../../config/env.config';
|
|
||||||
import { IMessageUpModel, MessageUpdateRaw } from '../models';
|
|
||||||
import { IInsert, Repository } from '../abstract/abstract.repository';
|
|
||||||
import { join } from 'path';
|
|
||||||
import { opendirSync, readFileSync } from 'fs';
|
import { opendirSync, readFileSync } from 'fs';
|
||||||
|
import { join } from 'path';
|
||||||
|
|
||||||
|
import { ConfigService, StoreConf } from '../../config/env.config';
|
||||||
import { Logger } from '../../config/logger.config';
|
import { Logger } from '../../config/logger.config';
|
||||||
|
import { IInsert, Repository } from '../abstract/abstract.repository';
|
||||||
|
import { IMessageUpModel, MessageUpdateRaw } from '../models';
|
||||||
|
|
||||||
export class MessageUpQuery {
|
export class MessageUpQuery {
|
||||||
where: MessageUpdateRaw;
|
where: MessageUpdateRaw;
|
||||||
@@ -11,20 +12,13 @@ export class MessageUpQuery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class MessageUpRepository extends Repository {
|
export class MessageUpRepository extends Repository {
|
||||||
constructor(
|
constructor(private readonly messageUpModel: IMessageUpModel, private readonly configService: ConfigService) {
|
||||||
private readonly messageUpModel: IMessageUpModel,
|
|
||||||
private readonly configService: ConfigService,
|
|
||||||
) {
|
|
||||||
super(configService);
|
super(configService);
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly logger = new Logger('MessageUpRepository');
|
private readonly logger = new Logger('MessageUpRepository');
|
||||||
|
|
||||||
public async insert(
|
public async insert(data: MessageUpdateRaw[], instanceName: string, saveDb?: boolean): Promise<IInsert> {
|
||||||
data: MessageUpdateRaw[],
|
|
||||||
instanceName: string,
|
|
||||||
saveDb?: boolean,
|
|
||||||
): Promise<IInsert> {
|
|
||||||
this.logger.verbose('inserting message up');
|
this.logger.verbose('inserting message up');
|
||||||
|
|
||||||
if (data.length === 0) {
|
if (data.length === 0) {
|
||||||
@@ -54,10 +48,7 @@ export class MessageUpRepository extends Repository {
|
|||||||
data: update,
|
data: update,
|
||||||
});
|
});
|
||||||
this.logger.verbose(
|
this.logger.verbose(
|
||||||
'message up saved to store in path: ' +
|
'message up saved to store in path: ' + join(this.storePath, 'message-up', instanceName) + '/' + update.id,
|
||||||
join(this.storePath, 'message-up', instanceName) +
|
|
||||||
'/' +
|
|
||||||
update.id,
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -91,42 +82,32 @@ export class MessageUpRepository extends Repository {
|
|||||||
|
|
||||||
messageUpdate.push(
|
messageUpdate.push(
|
||||||
JSON.parse(
|
JSON.parse(
|
||||||
readFileSync(
|
readFileSync(join(this.storePath, 'message-up', query.where.owner, query.where.id + '.json'), {
|
||||||
join(
|
encoding: 'utf-8',
|
||||||
this.storePath,
|
}),
|
||||||
'message-up',
|
|
||||||
query.where.owner,
|
|
||||||
query.where.id + '.json',
|
|
||||||
),
|
|
||||||
{ encoding: 'utf-8' },
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
this.logger.verbose('finding message up in store by owner');
|
this.logger.verbose('finding message up in store by owner');
|
||||||
|
|
||||||
const openDir = opendirSync(
|
const openDir = opendirSync(join(this.storePath, 'message-up', query.where.owner), {
|
||||||
join(this.storePath, 'message-up', query.where.owner),
|
encoding: 'utf-8',
|
||||||
{ encoding: 'utf-8' },
|
});
|
||||||
);
|
|
||||||
|
|
||||||
for await (const dirent of openDir) {
|
for await (const dirent of openDir) {
|
||||||
if (dirent.isFile()) {
|
if (dirent.isFile()) {
|
||||||
messageUpdate.push(
|
messageUpdate.push(
|
||||||
JSON.parse(
|
JSON.parse(
|
||||||
readFileSync(
|
readFileSync(join(this.storePath, 'message-up', query.where.owner, dirent.name), {
|
||||||
join(this.storePath, 'message-up', query.where.owner, dirent.name),
|
encoding: 'utf-8',
|
||||||
{ encoding: 'utf-8' },
|
}),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.verbose(
|
this.logger.verbose('message up found in store: ' + messageUpdate.length + ' message up');
|
||||||
'message up found in store: ' + messageUpdate.length + ' message up',
|
|
||||||
);
|
|
||||||
return messageUpdate
|
return messageUpdate
|
||||||
.sort((x, y) => {
|
.sort((x, y) => {
|
||||||
return y.datetime - x.datetime;
|
return y.datetime - x.datetime;
|
||||||
|
|||||||
62
src/whatsapp/repository/proxy.repository.ts
Normal file
62
src/whatsapp/repository/proxy.repository.ts
Normal 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 {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
62
src/whatsapp/repository/rabbitmq.repository.ts
Normal file
62
src/whatsapp/repository/rabbitmq.repository.ts
Normal 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 {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,17 +1,21 @@
|
|||||||
import { MessageRepository } from './message.repository';
|
|
||||||
import { ChatRepository } from './chat.repository';
|
|
||||||
import { ContactRepository } from './contact.repository';
|
|
||||||
import { MessageUpRepository } from './messageUp.repository';
|
|
||||||
import { MongoClient } from 'mongodb';
|
|
||||||
import { WebhookRepository } from './webhook.repository';
|
|
||||||
import { ChatwootRepository } from './chatwoot.repository';
|
|
||||||
import { SettingsRepository } from './settings.repository';
|
|
||||||
|
|
||||||
import { AuthRepository } from './auth.repository';
|
|
||||||
import { Auth, ConfigService, Database } from '../../config/env.config';
|
|
||||||
import { join } from 'path';
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
|
import { MongoClient } from 'mongodb';
|
||||||
|
import { join } from 'path';
|
||||||
|
|
||||||
|
import { Auth, ConfigService, Database } from '../../config/env.config';
|
||||||
import { Logger } from '../../config/logger.config';
|
import { Logger } from '../../config/logger.config';
|
||||||
|
import { AuthRepository } from './auth.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 { TypebotRepository } from './typebot.repository';
|
||||||
|
import { WebhookRepository } from './webhook.repository';
|
||||||
|
import { WebsocketRepository } from './websocket.repository';
|
||||||
export class RepositoryBroker {
|
export class RepositoryBroker {
|
||||||
constructor(
|
constructor(
|
||||||
public readonly message: MessageRepository,
|
public readonly message: MessageRepository,
|
||||||
@@ -21,6 +25,10 @@ export class RepositoryBroker {
|
|||||||
public readonly webhook: WebhookRepository,
|
public readonly webhook: WebhookRepository,
|
||||||
public readonly chatwoot: ChatwootRepository,
|
public readonly chatwoot: ChatwootRepository,
|
||||||
public readonly settings: SettingsRepository,
|
public readonly settings: SettingsRepository,
|
||||||
|
public readonly websocket: WebsocketRepository,
|
||||||
|
public readonly rabbitmq: RabbitmqRepository,
|
||||||
|
public readonly typebot: TypebotRepository,
|
||||||
|
public readonly proxy: ProxyRepository,
|
||||||
public readonly auth: AuthRepository,
|
public readonly auth: AuthRepository,
|
||||||
private configService: ConfigService,
|
private configService: ConfigService,
|
||||||
dbServer?: MongoClient,
|
dbServer?: MongoClient,
|
||||||
@@ -43,11 +51,7 @@ export class RepositoryBroker {
|
|||||||
|
|
||||||
this.logger.verbose('creating store path: ' + storePath);
|
this.logger.verbose('creating store path: ' + storePath);
|
||||||
try {
|
try {
|
||||||
const authDir = join(
|
const authDir = join(storePath, 'auth', this.configService.get<Auth>('AUTHENTICATION').TYPE);
|
||||||
storePath,
|
|
||||||
'auth',
|
|
||||||
this.configService.get<Auth>('AUTHENTICATION').TYPE,
|
|
||||||
);
|
|
||||||
const chatsDir = join(storePath, 'chats');
|
const chatsDir = join(storePath, 'chats');
|
||||||
const contactsDir = join(storePath, 'contacts');
|
const contactsDir = join(storePath, 'contacts');
|
||||||
const messagesDir = join(storePath, 'messages');
|
const messagesDir = join(storePath, 'messages');
|
||||||
@@ -55,6 +59,10 @@ export class RepositoryBroker {
|
|||||||
const webhookDir = join(storePath, 'webhook');
|
const webhookDir = join(storePath, 'webhook');
|
||||||
const chatwootDir = join(storePath, 'chatwoot');
|
const chatwootDir = join(storePath, 'chatwoot');
|
||||||
const settingsDir = join(storePath, 'settings');
|
const settingsDir = join(storePath, 'settings');
|
||||||
|
const websocketDir = join(storePath, 'websocket');
|
||||||
|
const rabbitmqDir = join(storePath, 'rabbitmq');
|
||||||
|
const typebotDir = join(storePath, 'typebot');
|
||||||
|
const proxyDir = join(storePath, 'proxy');
|
||||||
const tempDir = join(storePath, 'temp');
|
const tempDir = join(storePath, 'temp');
|
||||||
|
|
||||||
if (!fs.existsSync(authDir)) {
|
if (!fs.existsSync(authDir)) {
|
||||||
@@ -89,6 +97,22 @@ export class RepositoryBroker {
|
|||||||
this.logger.verbose('creating settings dir: ' + settingsDir);
|
this.logger.verbose('creating settings dir: ' + settingsDir);
|
||||||
fs.mkdirSync(settingsDir, { recursive: true });
|
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(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(tempDir)) {
|
if (!fs.existsSync(tempDir)) {
|
||||||
this.logger.verbose('creating temp dir: ' + tempDir);
|
this.logger.verbose('creating temp dir: ' + tempDir);
|
||||||
fs.mkdirSync(tempDir, { recursive: true });
|
fs.mkdirSync(tempDir, { recursive: true });
|
||||||
@@ -97,6 +121,7 @@ export class RepositoryBroker {
|
|||||||
this.logger.error(error);
|
this.logger.error(error);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
try {
|
||||||
const storePath = join(process.cwd(), 'store');
|
const storePath = join(process.cwd(), 'store');
|
||||||
|
|
||||||
this.logger.verbose('creating store path: ' + storePath);
|
this.logger.verbose('creating store path: ' + storePath);
|
||||||
@@ -112,7 +137,6 @@ export class RepositoryBroker {
|
|||||||
this.logger.verbose('creating temp dir: ' + tempDir);
|
this.logger.verbose('creating temp dir: ' + tempDir);
|
||||||
fs.mkdirSync(tempDir, { recursive: true });
|
fs.mkdirSync(tempDir, { recursive: true });
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.error(error);
|
this.logger.error(error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
import { IInsert, Repository } from '../abstract/abstract.repository';
|
|
||||||
import { ConfigService } from '../../config/env.config';
|
|
||||||
import { join } from 'path';
|
|
||||||
import { readFileSync } from 'fs';
|
import { readFileSync } from 'fs';
|
||||||
import { ISettingsModel, SettingsRaw } from '../models';
|
import { join } from 'path';
|
||||||
|
|
||||||
|
import { ConfigService } from '../../config/env.config';
|
||||||
import { Logger } from '../../config/logger.config';
|
import { Logger } from '../../config/logger.config';
|
||||||
|
import { IInsert, Repository } from '../abstract/abstract.repository';
|
||||||
|
import { ISettingsModel, SettingsRaw } from '../models';
|
||||||
|
|
||||||
export class SettingsRepository extends Repository {
|
export class SettingsRepository extends Repository {
|
||||||
constructor(
|
constructor(private readonly settingsModel: ISettingsModel, private readonly configService: ConfigService) {
|
||||||
private readonly settingsModel: ISettingsModel,
|
|
||||||
private readonly configService: ConfigService,
|
|
||||||
) {
|
|
||||||
super(configService);
|
super(configService);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,15 +18,9 @@ export class SettingsRepository extends Repository {
|
|||||||
this.logger.verbose('creating settings');
|
this.logger.verbose('creating settings');
|
||||||
if (this.dbSettings.ENABLED) {
|
if (this.dbSettings.ENABLED) {
|
||||||
this.logger.verbose('saving settings to db');
|
this.logger.verbose('saving settings to db');
|
||||||
const insert = await this.settingsModel.replaceOne(
|
const insert = await this.settingsModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
|
||||||
{ _id: instance },
|
|
||||||
{ ...data },
|
|
||||||
{ upsert: true },
|
|
||||||
);
|
|
||||||
|
|
||||||
this.logger.verbose(
|
this.logger.verbose('settings saved to db: ' + insert.modifiedCount + ' settings');
|
||||||
'settings saved to db: ' + insert.modifiedCount + ' settings',
|
|
||||||
);
|
|
||||||
return { insertCount: insert.modifiedCount };
|
return { insertCount: insert.modifiedCount };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,12 +32,7 @@ export class SettingsRepository extends Repository {
|
|||||||
data,
|
data,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.logger.verbose(
|
this.logger.verbose('settings saved to store in path: ' + join(this.storePath, 'settings') + '/' + instance);
|
||||||
'settings saved to store in path: ' +
|
|
||||||
join(this.storePath, 'settings') +
|
|
||||||
'/' +
|
|
||||||
instance,
|
|
||||||
);
|
|
||||||
|
|
||||||
this.logger.verbose('settings created');
|
this.logger.verbose('settings created');
|
||||||
return { insertCount: 1 };
|
return { insertCount: 1 };
|
||||||
|
|||||||
68
src/whatsapp/repository/typebot.repository.ts
Normal file
68
src/whatsapp/repository/typebot.repository.ts
Normal 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: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,13 @@
|
|||||||
import { IInsert, Repository } from '../abstract/abstract.repository';
|
|
||||||
import { ConfigService } from '../../config/env.config';
|
|
||||||
import { join } from 'path';
|
|
||||||
import { readFileSync } from 'fs';
|
import { readFileSync } from 'fs';
|
||||||
import { IWebhookModel, WebhookRaw } from '../models';
|
import { join } from 'path';
|
||||||
|
|
||||||
|
import { ConfigService } from '../../config/env.config';
|
||||||
import { Logger } from '../../config/logger.config';
|
import { Logger } from '../../config/logger.config';
|
||||||
|
import { IInsert, Repository } from '../abstract/abstract.repository';
|
||||||
|
import { IWebhookModel, WebhookRaw } from '../models';
|
||||||
|
|
||||||
export class WebhookRepository extends Repository {
|
export class WebhookRepository extends Repository {
|
||||||
constructor(
|
constructor(private readonly webhookModel: IWebhookModel, private readonly configService: ConfigService) {
|
||||||
private readonly webhookModel: IWebhookModel,
|
|
||||||
private readonly configService: ConfigService,
|
|
||||||
) {
|
|
||||||
super(configService);
|
super(configService);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,11 +18,7 @@ export class WebhookRepository extends Repository {
|
|||||||
this.logger.verbose('creating webhook');
|
this.logger.verbose('creating webhook');
|
||||||
if (this.dbSettings.ENABLED) {
|
if (this.dbSettings.ENABLED) {
|
||||||
this.logger.verbose('saving webhook to db');
|
this.logger.verbose('saving webhook to db');
|
||||||
const insert = await this.webhookModel.replaceOne(
|
const insert = await this.webhookModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
|
||||||
{ _id: instance },
|
|
||||||
{ ...data },
|
|
||||||
{ upsert: true },
|
|
||||||
);
|
|
||||||
|
|
||||||
this.logger.verbose('webhook saved to db: ' + insert.modifiedCount + ' webhook');
|
this.logger.verbose('webhook saved to db: ' + insert.modifiedCount + ' webhook');
|
||||||
return { insertCount: insert.modifiedCount };
|
return { insertCount: insert.modifiedCount };
|
||||||
@@ -38,12 +32,7 @@ export class WebhookRepository extends Repository {
|
|||||||
data,
|
data,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.logger.verbose(
|
this.logger.verbose('webhook saved to store in path: ' + join(this.storePath, 'webhook') + '/' + instance);
|
||||||
'webhook saved to store in path: ' +
|
|
||||||
join(this.storePath, 'webhook') +
|
|
||||||
'/' +
|
|
||||||
instance,
|
|
||||||
);
|
|
||||||
|
|
||||||
this.logger.verbose('webhook created');
|
this.logger.verbose('webhook created');
|
||||||
return { insertCount: 1 };
|
return { insertCount: 1 };
|
||||||
|
|||||||
62
src/whatsapp/repository/websocket.repository.ts
Normal file
62
src/whatsapp/repository/websocket.repository.ts
Normal 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 {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
import { RequestHandler, Router } from 'express';
|
import { RequestHandler, Router } from 'express';
|
||||||
|
|
||||||
|
import { Logger } from '../../config/logger.config';
|
||||||
import {
|
import {
|
||||||
archiveChatSchema,
|
archiveChatSchema,
|
||||||
contactValidateSchema,
|
contactValidateSchema,
|
||||||
@@ -13,9 +15,11 @@ import {
|
|||||||
readMessageSchema,
|
readMessageSchema,
|
||||||
whatsappNumberSchema,
|
whatsappNumberSchema,
|
||||||
} from '../../validate/validate.schema';
|
} from '../../validate/validate.schema';
|
||||||
|
import { RouterBroker } from '../abstract/abstract.router';
|
||||||
import {
|
import {
|
||||||
ArchiveChatDto,
|
ArchiveChatDto,
|
||||||
DeleteMessage,
|
DeleteMessage,
|
||||||
|
getBase64FromMediaMessageDto,
|
||||||
NumberDto,
|
NumberDto,
|
||||||
PrivacySettingDto,
|
PrivacySettingDto,
|
||||||
ProfileNameDto,
|
ProfileNameDto,
|
||||||
@@ -23,17 +27,13 @@ import {
|
|||||||
ProfileStatusDto,
|
ProfileStatusDto,
|
||||||
ReadMessageDto,
|
ReadMessageDto,
|
||||||
WhatsAppNumberDto,
|
WhatsAppNumberDto,
|
||||||
getBase64FromMediaMessageDto,
|
|
||||||
} from '../dto/chat.dto';
|
} from '../dto/chat.dto';
|
||||||
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
import { ContactQuery } from '../repository/contact.repository';
|
import { ContactQuery } from '../repository/contact.repository';
|
||||||
import { MessageQuery } from '../repository/message.repository';
|
import { MessageQuery } from '../repository/message.repository';
|
||||||
import { chatController } from '../whatsapp.module';
|
|
||||||
import { RouterBroker } from '../abstract/abstract.router';
|
|
||||||
import { HttpStatus } from './index.router';
|
|
||||||
import { MessageUpQuery } from '../repository/messageUp.repository';
|
import { MessageUpQuery } from '../repository/messageUp.repository';
|
||||||
import { proto } from '@whiskeysockets/baileys';
|
import { chatController } from '../whatsapp.module';
|
||||||
import { InstanceDto } from '../dto/instance.dto';
|
import { HttpStatus } from './index.router';
|
||||||
import { Logger } from '../../config/logger.config';
|
|
||||||
|
|
||||||
const logger = new Logger('ChatRouter');
|
const logger = new Logger('ChatRouter');
|
||||||
|
|
||||||
@@ -92,10 +92,7 @@ export class ChatRouter extends RouterBroker {
|
|||||||
|
|
||||||
return res.status(HttpStatus.CREATED).json(response);
|
return res.status(HttpStatus.CREATED).json(response);
|
||||||
})
|
})
|
||||||
.delete(
|
.delete(this.routerPath('deleteMessageForEveryone'), ...guards, async (req, res) => {
|
||||||
this.routerPath('deleteMessageForEveryone'),
|
|
||||||
...guards,
|
|
||||||
async (req, res) => {
|
|
||||||
logger.verbose('request received in deleteMessageForEveryone');
|
logger.verbose('request received in deleteMessageForEveryone');
|
||||||
logger.verbose('request body: ');
|
logger.verbose('request body: ');
|
||||||
logger.verbose(req.body);
|
logger.verbose(req.body);
|
||||||
@@ -111,8 +108,7 @@ export class ChatRouter extends RouterBroker {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return res.status(HttpStatus.CREATED).json(response);
|
return res.status(HttpStatus.CREATED).json(response);
|
||||||
},
|
})
|
||||||
)
|
|
||||||
.post(this.routerPath('fetchProfilePictureUrl'), ...guards, async (req, res) => {
|
.post(this.routerPath('fetchProfilePictureUrl'), ...guards, async (req, res) => {
|
||||||
logger.verbose('request received in fetchProfilePictureUrl');
|
logger.verbose('request received in fetchProfilePictureUrl');
|
||||||
logger.verbose('request body: ');
|
logger.verbose('request body: ');
|
||||||
@@ -176,8 +172,7 @@ export class ChatRouter extends RouterBroker {
|
|||||||
request: req,
|
request: req,
|
||||||
schema: null,
|
schema: null,
|
||||||
ClassRef: getBase64FromMediaMessageDto,
|
ClassRef: getBase64FromMediaMessageDto,
|
||||||
execute: (instance, data) =>
|
execute: (instance, data) => chatController.getBase64FromMediaMessage(instance, data),
|
||||||
chatController.getBase64FromMediaMessage(instance, data),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.status(HttpStatus.CREATED).json(response);
|
return res.status(HttpStatus.CREATED).json(response);
|
||||||
@@ -263,8 +258,7 @@ export class ChatRouter extends RouterBroker {
|
|||||||
request: req,
|
request: req,
|
||||||
schema: privacySettingsSchema,
|
schema: privacySettingsSchema,
|
||||||
ClassRef: PrivacySettingDto,
|
ClassRef: PrivacySettingDto,
|
||||||
execute: (instance, data) =>
|
execute: (instance, data) => chatController.updatePrivacySettings(instance, data),
|
||||||
chatController.updatePrivacySettings(instance, data),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.status(HttpStatus.CREATED).json(response);
|
return res.status(HttpStatus.CREATED).json(response);
|
||||||
@@ -281,8 +275,7 @@ export class ChatRouter extends RouterBroker {
|
|||||||
request: req,
|
request: req,
|
||||||
schema: profilePictureSchema,
|
schema: profilePictureSchema,
|
||||||
ClassRef: ProfilePictureDto,
|
ClassRef: ProfilePictureDto,
|
||||||
execute: (instance, data) =>
|
execute: (instance, data) => chatController.fetchBusinessProfile(instance, data),
|
||||||
chatController.fetchBusinessProfile(instance, data),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.status(HttpStatus.OK).json(response);
|
return res.status(HttpStatus.OK).json(response);
|
||||||
@@ -333,8 +326,7 @@ export class ChatRouter extends RouterBroker {
|
|||||||
request: req,
|
request: req,
|
||||||
schema: profilePictureSchema,
|
schema: profilePictureSchema,
|
||||||
ClassRef: ProfilePictureDto,
|
ClassRef: ProfilePictureDto,
|
||||||
execute: (instance, data) =>
|
execute: (instance, data) => chatController.updateProfilePicture(instance, data),
|
||||||
chatController.updateProfilePicture(instance, data),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.status(HttpStatus.OK).json(response);
|
return res.status(HttpStatus.OK).json(response);
|
||||||
@@ -351,8 +343,7 @@ export class ChatRouter extends RouterBroker {
|
|||||||
request: req,
|
request: req,
|
||||||
schema: profilePictureSchema,
|
schema: profilePictureSchema,
|
||||||
ClassRef: ProfilePictureDto,
|
ClassRef: ProfilePictureDto,
|
||||||
execute: (instance, data) =>
|
execute: (instance) => chatController.removeProfilePicture(instance),
|
||||||
chatController.removeProfilePicture(instance, data),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.status(HttpStatus.OK).json(response);
|
return res.status(HttpStatus.OK).json(response);
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import { RequestHandler, Router } from 'express';
|
import { RequestHandler, Router } from 'express';
|
||||||
import { instanceNameSchema, chatwootSchema } from '../../validate/validate.schema';
|
|
||||||
import { RouterBroker } from '../abstract/abstract.router';
|
|
||||||
import { InstanceDto } from '../dto/instance.dto';
|
|
||||||
import { ChatwootDto } from '../dto/chatwoot.dto';
|
|
||||||
import { chatwootController } from '../whatsapp.module';
|
|
||||||
import { ChatwootService } from '../services/chatwoot.service';
|
|
||||||
import { HttpStatus } from './index.router';
|
|
||||||
import { Logger } from '../../config/logger.config';
|
import { Logger } from '../../config/logger.config';
|
||||||
|
import { chatwootSchema, instanceNameSchema } from '../../validate/validate.schema';
|
||||||
|
import { RouterBroker } from '../abstract/abstract.router';
|
||||||
|
import { ChatwootDto } from '../dto/chatwoot.dto';
|
||||||
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
|
// import { ChatwootService } from '../services/chatwoot.service';
|
||||||
|
import { chatwootController } from '../whatsapp.module';
|
||||||
|
import { HttpStatus } from './index.router';
|
||||||
|
|
||||||
const logger = new Logger('ChatwootRouter');
|
const logger = new Logger('ChatwootRouter');
|
||||||
|
|
||||||
|
|||||||
@@ -1,34 +1,35 @@
|
|||||||
import { RequestHandler, Router } from 'express';
|
import { RequestHandler, Router } from 'express';
|
||||||
|
|
||||||
|
import { Logger } from '../../config/logger.config';
|
||||||
import {
|
import {
|
||||||
createGroupSchema,
|
createGroupSchema,
|
||||||
|
getParticipantsSchema,
|
||||||
|
groupInviteSchema,
|
||||||
groupJidSchema,
|
groupJidSchema,
|
||||||
updateParticipantsSchema,
|
groupSendInviteSchema,
|
||||||
updateSettingsSchema,
|
|
||||||
toggleEphemeralSchema,
|
toggleEphemeralSchema,
|
||||||
|
updateGroupDescriptionSchema,
|
||||||
updateGroupPictureSchema,
|
updateGroupPictureSchema,
|
||||||
updateGroupSubjectSchema,
|
updateGroupSubjectSchema,
|
||||||
updateGroupDescriptionSchema,
|
updateParticipantsSchema,
|
||||||
groupInviteSchema,
|
updateSettingsSchema,
|
||||||
groupSendInviteSchema,
|
|
||||||
getParticipantsSchema,
|
|
||||||
} from '../../validate/validate.schema';
|
} from '../../validate/validate.schema';
|
||||||
import { RouterBroker } from '../abstract/abstract.router';
|
import { RouterBroker } from '../abstract/abstract.router';
|
||||||
import {
|
import {
|
||||||
CreateGroupDto,
|
CreateGroupDto,
|
||||||
|
GetParticipant,
|
||||||
|
GroupDescriptionDto,
|
||||||
GroupInvite,
|
GroupInvite,
|
||||||
GroupJid,
|
GroupJid,
|
||||||
GroupPictureDto,
|
GroupPictureDto,
|
||||||
|
GroupSendInvite,
|
||||||
GroupSubjectDto,
|
GroupSubjectDto,
|
||||||
GroupDescriptionDto,
|
GroupToggleEphemeralDto,
|
||||||
GroupUpdateParticipantDto,
|
GroupUpdateParticipantDto,
|
||||||
GroupUpdateSettingDto,
|
GroupUpdateSettingDto,
|
||||||
GroupToggleEphemeralDto,
|
|
||||||
GroupSendInvite,
|
|
||||||
GetParticipant,
|
|
||||||
} from '../dto/group.dto';
|
} from '../dto/group.dto';
|
||||||
import { groupController } from '../whatsapp.module';
|
import { groupController } from '../whatsapp.module';
|
||||||
import { HttpStatus } from './index.router';
|
import { HttpStatus } from './index.router';
|
||||||
import { Logger } from '../../config/logger.config';
|
|
||||||
|
|
||||||
const logger = new Logger('GroupRouter');
|
const logger = new Logger('GroupRouter');
|
||||||
|
|
||||||
@@ -96,8 +97,7 @@ export class GroupRouter extends RouterBroker {
|
|||||||
request: req,
|
request: req,
|
||||||
schema: updateGroupDescriptionSchema,
|
schema: updateGroupDescriptionSchema,
|
||||||
ClassRef: GroupDescriptionDto,
|
ClassRef: GroupDescriptionDto,
|
||||||
execute: (instance, data) =>
|
execute: (instance, data) => groupController.updateGroupDescription(instance, data),
|
||||||
groupController.updateGroupDescription(instance, data),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
res.status(HttpStatus.CREATED).json(response);
|
res.status(HttpStatus.CREATED).json(response);
|
||||||
|
|||||||
@@ -1,16 +1,21 @@
|
|||||||
import { Router } from 'express';
|
import { Router } from 'express';
|
||||||
|
import fs from 'fs';
|
||||||
|
|
||||||
import { Auth, configService } from '../../config/env.config';
|
import { Auth, configService } from '../../config/env.config';
|
||||||
import { instanceExistsGuard, instanceLoggedGuard } from '../guards/instance.guard';
|
|
||||||
import { authGuard } from '../guards/auth.guard';
|
import { authGuard } from '../guards/auth.guard';
|
||||||
|
import { instanceExistsGuard, instanceLoggedGuard } from '../guards/instance.guard';
|
||||||
import { ChatRouter } from './chat.router';
|
import { ChatRouter } from './chat.router';
|
||||||
|
import { ChatwootRouter } from './chatwoot.router';
|
||||||
import { GroupRouter } from './group.router';
|
import { GroupRouter } from './group.router';
|
||||||
import { InstanceRouter } from './instance.router';
|
import { InstanceRouter } from './instance.router';
|
||||||
|
import { ProxyRouter } from './proxy.router';
|
||||||
|
import { RabbitmqRouter } from './rabbitmq.router';
|
||||||
import { MessageRouter } from './sendMessage.router';
|
import { MessageRouter } from './sendMessage.router';
|
||||||
|
import { SettingsRouter } from './settings.router';
|
||||||
|
import { TypebotRouter } from './typebot.router';
|
||||||
import { ViewsRouter } from './view.router';
|
import { ViewsRouter } from './view.router';
|
||||||
import { WebhookRouter } from './webhook.router';
|
import { WebhookRouter } from './webhook.router';
|
||||||
import { ChatwootRouter } from './chatwoot.router';
|
import { WebsocketRouter } from './websocket.router';
|
||||||
import fs from 'fs';
|
|
||||||
import { SettingsRouter } from './settings.router';
|
|
||||||
|
|
||||||
enum HttpStatus {
|
enum HttpStatus {
|
||||||
OK = 200,
|
OK = 200,
|
||||||
@@ -36,16 +41,17 @@ router
|
|||||||
version: packageJson.version,
|
version: packageJson.version,
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.use(
|
.use('/instance', new InstanceRouter(configService, ...guards).router)
|
||||||
'/instance',
|
.use('/manager', new ViewsRouter().router)
|
||||||
new InstanceRouter(configService, ...guards).router,
|
|
||||||
new ViewsRouter(instanceExistsGuard).router,
|
|
||||||
)
|
|
||||||
.use('/message', new MessageRouter(...guards).router)
|
.use('/message', new MessageRouter(...guards).router)
|
||||||
.use('/chat', new ChatRouter(...guards).router)
|
.use('/chat', new ChatRouter(...guards).router)
|
||||||
.use('/group', new GroupRouter(...guards).router)
|
.use('/group', new GroupRouter(...guards).router)
|
||||||
.use('/webhook', new WebhookRouter(...guards).router)
|
.use('/webhook', new WebhookRouter(...guards).router)
|
||||||
.use('/chatwoot', new ChatwootRouter(...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('/typebot', new TypebotRouter(...guards).router)
|
||||||
|
.use('/proxy', new ProxyRouter(...guards).router);
|
||||||
|
|
||||||
export { router, HttpStatus };
|
export { HttpStatus, router };
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
import { RequestHandler, Router } from 'express';
|
import { RequestHandler, Router } from 'express';
|
||||||
import { instanceNameSchema, oldTokenSchema } from '../../validate/validate.schema';
|
|
||||||
import { InstanceDto } from '../dto/instance.dto';
|
|
||||||
import { instanceController } from '../whatsapp.module';
|
|
||||||
import { RouterBroker } from '../abstract/abstract.router';
|
|
||||||
import { HttpStatus } from './index.router';
|
|
||||||
import { OldToken } from '../services/auth.service';
|
|
||||||
import { Auth, ConfigService, Database } from '../../config/env.config';
|
import { Auth, ConfigService, Database } from '../../config/env.config';
|
||||||
import { dbserver } from '../../db/db.connect';
|
|
||||||
import { Logger } from '../../config/logger.config';
|
import { Logger } from '../../config/logger.config';
|
||||||
|
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';
|
||||||
|
import { OldToken } from '../services/auth.service';
|
||||||
|
import { instanceController } from '../whatsapp.module';
|
||||||
|
import { HttpStatus } from './index.router';
|
||||||
|
|
||||||
const logger = new Logger('InstanceRouter');
|
const logger = new Logger('InstanceRouter');
|
||||||
|
|
||||||
@@ -162,17 +163,13 @@ export class InstanceRouter extends RouterBroker {
|
|||||||
await dbserver.dropDatabase();
|
await dbserver.dropDatabase();
|
||||||
return res
|
return res
|
||||||
.status(HttpStatus.CREATED)
|
.status(HttpStatus.CREATED)
|
||||||
.json({ error: false, message: 'Database deleted' });
|
.json({ status: 'SUCCESS', error: false, response: { message: 'database deleted' } });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return res
|
return res.status(HttpStatus.INTERNAL_SERVER_ERROR).json({ error: true, message: error.message });
|
||||||
.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
|
||||||
.json({ error: true, message: error.message });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res
|
return res.status(HttpStatus.INTERNAL_SERVER_ERROR).json({ error: true, message: 'Database is not enabled' });
|
||||||
.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
|
||||||
.json({ error: true, message: 'Database is not enabled' });
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
52
src/whatsapp/routers/proxy.router.ts
Normal file
52
src/whatsapp/routers/proxy.router.ts
Normal 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();
|
||||||
|
}
|
||||||
52
src/whatsapp/routers/rabbitmq.router.ts
Normal file
52
src/whatsapp/routers/rabbitmq.router.ts
Normal 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();
|
||||||
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
import { RequestHandler, Router } from 'express';
|
import { RequestHandler, Router } from 'express';
|
||||||
|
|
||||||
|
import { Logger } from '../../config/logger.config';
|
||||||
import {
|
import {
|
||||||
audioMessageSchema,
|
audioMessageSchema,
|
||||||
buttonMessageSchema,
|
buttonMessageSchema,
|
||||||
@@ -12,6 +14,7 @@ import {
|
|||||||
stickerMessageSchema,
|
stickerMessageSchema,
|
||||||
textMessageSchema,
|
textMessageSchema,
|
||||||
} from '../../validate/validate.schema';
|
} from '../../validate/validate.schema';
|
||||||
|
import { RouterBroker } from '../abstract/abstract.router';
|
||||||
import {
|
import {
|
||||||
SendAudioDto,
|
SendAudioDto,
|
||||||
SendButtonDto,
|
SendButtonDto,
|
||||||
@@ -26,9 +29,7 @@ import {
|
|||||||
SendTextDto,
|
SendTextDto,
|
||||||
} from '../dto/sendMessage.dto';
|
} from '../dto/sendMessage.dto';
|
||||||
import { sendMessageController } from '../whatsapp.module';
|
import { sendMessageController } from '../whatsapp.module';
|
||||||
import { RouterBroker } from '../abstract/abstract.router';
|
|
||||||
import { HttpStatus } from './index.router';
|
import { HttpStatus } from './index.router';
|
||||||
import { Logger } from '../../config/logger.config';
|
|
||||||
|
|
||||||
const logger = new Logger('MessageRouter');
|
const logger = new Logger('MessageRouter');
|
||||||
|
|
||||||
@@ -79,8 +80,7 @@ export class MessageRouter extends RouterBroker {
|
|||||||
request: req,
|
request: req,
|
||||||
schema: audioMessageSchema,
|
schema: audioMessageSchema,
|
||||||
ClassRef: SendMediaDto,
|
ClassRef: SendMediaDto,
|
||||||
execute: (instance, data) =>
|
execute: (instance, data) => sendMessageController.sendWhatsAppAudio(instance, data),
|
||||||
sendMessageController.sendWhatsAppAudio(instance, data),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.status(HttpStatus.CREATED).json(response);
|
return res.status(HttpStatus.CREATED).json(response);
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import { RequestHandler, Router } from 'express';
|
import { RequestHandler, Router } from 'express';
|
||||||
|
|
||||||
|
import { Logger } from '../../config/logger.config';
|
||||||
import { instanceNameSchema, settingsSchema } from '../../validate/validate.schema';
|
import { instanceNameSchema, settingsSchema } from '../../validate/validate.schema';
|
||||||
import { RouterBroker } from '../abstract/abstract.router';
|
import { RouterBroker } from '../abstract/abstract.router';
|
||||||
import { InstanceDto } from '../dto/instance.dto';
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
import { SettingsDto } from '../dto/settings.dto';
|
import { SettingsDto } from '../dto/settings.dto';
|
||||||
|
// import { SettingsService } from '../services/settings.service';
|
||||||
import { settingsController } from '../whatsapp.module';
|
import { settingsController } from '../whatsapp.module';
|
||||||
import { SettingsService } from '../services/settings.service';
|
|
||||||
import { HttpStatus } from './index.router';
|
import { HttpStatus } from './index.router';
|
||||||
import { Logger } from '../../config/logger.config';
|
|
||||||
|
|
||||||
const logger = new Logger('SettingsRouter');
|
const logger = new Logger('SettingsRouter');
|
||||||
|
|
||||||
|
|||||||
89
src/whatsapp/routers/typebot.router.ts
Normal file
89
src/whatsapp/routers/typebot.router.ts
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
import { RequestHandler, Router } from 'express';
|
||||||
|
|
||||||
|
import { Logger } from '../../config/logger.config';
|
||||||
|
import {
|
||||||
|
instanceNameSchema,
|
||||||
|
typebotSchema,
|
||||||
|
typebotStartSchema,
|
||||||
|
typebotStatusSchema,
|
||||||
|
} from '../../validate/validate.schema';
|
||||||
|
import { RouterBroker } from '../abstract/abstract.router';
|
||||||
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
|
import { TypebotDto } from '../dto/typebot.dto';
|
||||||
|
import { typebotController } from '../whatsapp.module';
|
||||||
|
import { HttpStatus } from './index.router';
|
||||||
|
|
||||||
|
const logger = new Logger('TypebotRouter');
|
||||||
|
|
||||||
|
export class TypebotRouter extends RouterBroker {
|
||||||
|
constructor(...guards: RequestHandler[]) {
|
||||||
|
super();
|
||||||
|
this.router
|
||||||
|
.post(this.routerPath('set'), ...guards, async (req, res) => {
|
||||||
|
logger.verbose('request received in setTypebot');
|
||||||
|
logger.verbose('request body: ');
|
||||||
|
logger.verbose(req.body);
|
||||||
|
|
||||||
|
logger.verbose('request query: ');
|
||||||
|
logger.verbose(req.query);
|
||||||
|
const response = await this.dataValidate<TypebotDto>({
|
||||||
|
request: req,
|
||||||
|
schema: typebotSchema,
|
||||||
|
ClassRef: TypebotDto,
|
||||||
|
execute: (instance, data) => typebotController.createTypebot(instance, data),
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(HttpStatus.CREATED).json(response);
|
||||||
|
})
|
||||||
|
.get(this.routerPath('find'), ...guards, async (req, res) => {
|
||||||
|
logger.verbose('request received in findTypebot');
|
||||||
|
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) => typebotController.findTypebot(instance),
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(HttpStatus.OK).json(response);
|
||||||
|
})
|
||||||
|
.post(this.routerPath('changeStatus'), ...guards, async (req, res) => {
|
||||||
|
logger.verbose('request received in changeStatusTypebot');
|
||||||
|
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: typebotStatusSchema,
|
||||||
|
ClassRef: InstanceDto,
|
||||||
|
execute: (instance, data) => typebotController.changeStatus(instance, data),
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(HttpStatus.OK).json(response);
|
||||||
|
})
|
||||||
|
.post(this.routerPath('start'), ...guards, async (req, res) => {
|
||||||
|
logger.verbose('request received in startTypebot');
|
||||||
|
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: typebotStartSchema,
|
||||||
|
ClassRef: InstanceDto,
|
||||||
|
execute: (instance, data) => typebotController.startTypebot(instance, data),
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(HttpStatus.OK).json(response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly router = Router();
|
||||||
|
}
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
import { RequestHandler, Router } from 'express';
|
import { Router } from 'express';
|
||||||
|
|
||||||
import { RouterBroker } from '../abstract/abstract.router';
|
import { RouterBroker } from '../abstract/abstract.router';
|
||||||
import { viewsController } from '../whatsapp.module';
|
import { viewsController } from '../whatsapp.module';
|
||||||
|
|
||||||
export class ViewsRouter extends RouterBroker {
|
export class ViewsRouter extends RouterBroker {
|
||||||
constructor(...guards: RequestHandler[]) {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.router.get(this.routerPath('qrcode'), ...guards, (req, res) => {
|
this.router.get('/', (req, res) => {
|
||||||
return viewsController.qrcode(req, res);
|
return viewsController.manager(req, res);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import { RequestHandler, Router } from 'express';
|
import { RequestHandler, Router } from 'express';
|
||||||
|
|
||||||
|
import { Logger } from '../../config/logger.config';
|
||||||
import { instanceNameSchema, webhookSchema } from '../../validate/validate.schema';
|
import { instanceNameSchema, webhookSchema } from '../../validate/validate.schema';
|
||||||
import { RouterBroker } from '../abstract/abstract.router';
|
import { RouterBroker } from '../abstract/abstract.router';
|
||||||
import { InstanceDto } from '../dto/instance.dto';
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
import { WebhookDto } from '../dto/webhook.dto';
|
import { WebhookDto } from '../dto/webhook.dto';
|
||||||
import { webhookController } from '../whatsapp.module';
|
import { webhookController } from '../whatsapp.module';
|
||||||
import { HttpStatus } from './index.router';
|
import { HttpStatus } from './index.router';
|
||||||
import { Logger } from '../../config/logger.config';
|
|
||||||
|
|
||||||
const logger = new Logger('WebhookRouter');
|
const logger = new Logger('WebhookRouter');
|
||||||
|
|
||||||
|
|||||||
52
src/whatsapp/routers/websocket.router.ts
Normal file
52
src/whatsapp/routers/websocket.router.ts
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import { RequestHandler, Router } from 'express';
|
||||||
|
|
||||||
|
import { Logger } from '../../config/logger.config';
|
||||||
|
import { instanceNameSchema, websocketSchema } from '../../validate/validate.schema';
|
||||||
|
import { RouterBroker } from '../abstract/abstract.router';
|
||||||
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
|
import { WebsocketDto } from '../dto/websocket.dto';
|
||||||
|
import { websocketController } from '../whatsapp.module';
|
||||||
|
import { HttpStatus } from './index.router';
|
||||||
|
|
||||||
|
const logger = new Logger('WebsocketRouter');
|
||||||
|
|
||||||
|
export class WebsocketRouter extends RouterBroker {
|
||||||
|
constructor(...guards: RequestHandler[]) {
|
||||||
|
super();
|
||||||
|
this.router
|
||||||
|
.post(this.routerPath('set'), ...guards, async (req, res) => {
|
||||||
|
logger.verbose('request received in setWebsocket');
|
||||||
|
logger.verbose('request body: ');
|
||||||
|
logger.verbose(req.body);
|
||||||
|
|
||||||
|
logger.verbose('request query: ');
|
||||||
|
logger.verbose(req.query);
|
||||||
|
const response = await this.dataValidate<WebsocketDto>({
|
||||||
|
request: req,
|
||||||
|
schema: websocketSchema,
|
||||||
|
ClassRef: WebsocketDto,
|
||||||
|
execute: (instance, data) => websocketController.createWebsocket(instance, data),
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(HttpStatus.CREATED).json(response);
|
||||||
|
})
|
||||||
|
.get(this.routerPath('find'), ...guards, async (req, res) => {
|
||||||
|
logger.verbose('request received in findWebsocket');
|
||||||
|
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) => websocketController.findWebsocket(instance),
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(HttpStatus.OK).json(response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly router = Router();
|
||||||
|
}
|
||||||
@@ -1,14 +1,15 @@
|
|||||||
import { Auth, ConfigService, Webhook } from '../../config/env.config';
|
|
||||||
import { InstanceDto } from '../dto/instance.dto';
|
|
||||||
import { name as apiName } from '../../../package.json';
|
|
||||||
import { verify, sign } from 'jsonwebtoken';
|
|
||||||
import { Logger } from '../../config/logger.config';
|
|
||||||
import { v4 } from 'uuid';
|
|
||||||
import { isJWT } from 'class-validator';
|
|
||||||
import { BadRequestException } from '../../exceptions';
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { WAMonitoringService } from './monitor.service';
|
import { isJWT } from 'class-validator';
|
||||||
|
import { sign, verify } from 'jsonwebtoken';
|
||||||
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
|
import { name as apiName } from '../../../package.json';
|
||||||
|
import { Auth, ConfigService, Webhook } from '../../config/env.config';
|
||||||
|
import { Logger } from '../../config/logger.config';
|
||||||
|
import { BadRequestException } from '../../exceptions';
|
||||||
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
import { RepositoryBroker } from '../repository/repository.manager';
|
import { RepositoryBroker } from '../repository/repository.manager';
|
||||||
|
import { WAMonitoringService } from './monitor.service';
|
||||||
|
|
||||||
export type JwtPayload = {
|
export type JwtPayload = {
|
||||||
instanceName: string;
|
instanceName: string;
|
||||||
@@ -63,9 +64,7 @@ export class AuthService {
|
|||||||
private async apikey(instance: InstanceDto, token?: string) {
|
private async apikey(instance: InstanceDto, token?: string) {
|
||||||
const apikey = token ? token : v4().toUpperCase();
|
const apikey = token ? token : v4().toUpperCase();
|
||||||
|
|
||||||
this.logger.verbose(
|
this.logger.verbose(token ? 'APIKEY defined: ' + apikey : 'APIKEY created: ' + apikey);
|
||||||
token ? 'APIKEY defined: ' + apikey : 'APIKEY created: ' + apikey,
|
|
||||||
);
|
|
||||||
|
|
||||||
const auth = await this.repository.auth.create({ apikey }, instance.instanceName);
|
const auth = await this.repository.auth.create({ apikey }, instance.instanceName);
|
||||||
|
|
||||||
@@ -101,13 +100,9 @@ export class AuthService {
|
|||||||
public async generateHash(instance: InstanceDto, token?: string) {
|
public async generateHash(instance: InstanceDto, token?: string) {
|
||||||
const options = this.configService.get<Auth>('AUTHENTICATION');
|
const options = this.configService.get<Auth>('AUTHENTICATION');
|
||||||
|
|
||||||
this.logger.verbose(
|
this.logger.verbose('generating hash ' + options.TYPE + ' to instance: ' + instance.instanceName);
|
||||||
'generating hash ' + options.TYPE + ' to instance: ' + instance.instanceName,
|
|
||||||
);
|
|
||||||
|
|
||||||
return (await this[options.TYPE](instance, token)) as
|
return (await this[options.TYPE](instance, token)) as { jwt: string } | { apikey: string };
|
||||||
| { jwt: string }
|
|
||||||
| { apikey: string };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async refreshToken({ oldToken }: OldToken) {
|
public async refreshToken({ oldToken }: OldToken) {
|
||||||
@@ -150,10 +145,7 @@ export class AuthService {
|
|||||||
try {
|
try {
|
||||||
this.logger.verbose('checking webhook');
|
this.logger.verbose('checking webhook');
|
||||||
const webhook = await this.repository.webhook.find(decode.instanceName);
|
const webhook = await this.repository.webhook.find(decode.instanceName);
|
||||||
if (
|
if (webhook?.enabled && this.configService.get<Webhook>('WEBHOOK').EVENTS.NEW_JWT_TOKEN) {
|
||||||
webhook?.enabled &&
|
|
||||||
this.configService.get<Webhook>('WEBHOOK').EVENTS.NEW_JWT_TOKEN
|
|
||||||
) {
|
|
||||||
this.logger.verbose('sending webhook');
|
this.logger.verbose('sending webhook');
|
||||||
|
|
||||||
const httpService = axios.create({ baseURL: webhook.url });
|
const httpService = axios.create({ baseURL: webhook.url });
|
||||||
|
|||||||
@@ -1,19 +1,17 @@
|
|||||||
import { InstanceDto } from '../dto/instance.dto';
|
|
||||||
import path from 'path';
|
|
||||||
import { ChatwootDto } from '../dto/chatwoot.dto';
|
|
||||||
import { WAMonitoringService } from './monitor.service';
|
|
||||||
import { Logger } from '../../config/logger.config';
|
|
||||||
import ChatwootClient from '@figuro/chatwoot-sdk';
|
import ChatwootClient from '@figuro/chatwoot-sdk';
|
||||||
import { createReadStream, readFileSync, unlinkSync, writeFileSync } from 'fs';
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import FormData from 'form-data';
|
import FormData from 'form-data';
|
||||||
import { SendTextDto } from '../dto/sendMessage.dto';
|
import { createReadStream, readFileSync, unlinkSync, writeFileSync } from 'fs';
|
||||||
import mimeTypes from 'mime-types';
|
import mimeTypes from 'mime-types';
|
||||||
import { SendAudioDto } from '../dto/sendMessage.dto';
|
import path from 'path';
|
||||||
import { SendMediaDto } from '../dto/sendMessage.dto';
|
|
||||||
|
import { ConfigService } from '../../config/env.config';
|
||||||
|
import { Logger } from '../../config/logger.config';
|
||||||
import { ROOT_DIR } from '../../config/path.config';
|
import { ROOT_DIR } from '../../config/path.config';
|
||||||
import { ConfigService, HttpServer } from '../../config/env.config';
|
import { ChatwootDto } from '../dto/chatwoot.dto';
|
||||||
import { type } from 'os';
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
|
import { SendAudioDto, SendMediaDto, SendTextDto } from '../dto/sendMessage.dto';
|
||||||
|
import { WAMonitoringService } from './monitor.service';
|
||||||
|
|
||||||
export class ChatwootService {
|
export class ChatwootService {
|
||||||
private messageCacheFile: string;
|
private messageCacheFile: string;
|
||||||
@@ -23,10 +21,7 @@ export class ChatwootService {
|
|||||||
|
|
||||||
private provider: any;
|
private provider: any;
|
||||||
|
|
||||||
constructor(
|
constructor(private readonly waMonitor: WAMonitoringService, private readonly configService: ConfigService) {
|
||||||
private readonly waMonitor: WAMonitoringService,
|
|
||||||
private readonly configService: ConfigService,
|
|
||||||
) {
|
|
||||||
this.messageCache = new Set();
|
this.messageCache = new Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,9 +52,7 @@ export class ChatwootService {
|
|||||||
private async getProvider(instance: InstanceDto) {
|
private async getProvider(instance: InstanceDto) {
|
||||||
this.logger.verbose('get provider to instance: ' + instance.instanceName);
|
this.logger.verbose('get provider to instance: ' + instance.instanceName);
|
||||||
try {
|
try {
|
||||||
const provider = await this.waMonitor.waInstances[
|
const provider = await this.waMonitor.waInstances[instance.instanceName].findChatwoot();
|
||||||
instance.instanceName
|
|
||||||
].findChatwoot();
|
|
||||||
|
|
||||||
if (!provider) {
|
if (!provider) {
|
||||||
this.logger.warn('provider not found');
|
this.logger.warn('provider not found');
|
||||||
@@ -172,9 +165,7 @@ export class ChatwootService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.logger.verbose('check duplicate inbox');
|
this.logger.verbose('check duplicate inbox');
|
||||||
const checkDuplicate = findInbox.payload
|
const checkDuplicate = findInbox.payload.map((inbox) => inbox.name).includes(inboxName);
|
||||||
.map((inbox) => inbox.name)
|
|
||||||
.includes(inboxName);
|
|
||||||
|
|
||||||
let inboxId: number;
|
let inboxId: number;
|
||||||
|
|
||||||
@@ -220,6 +211,7 @@ export class ChatwootService {
|
|||||||
inboxId,
|
inboxId,
|
||||||
false,
|
false,
|
||||||
'EvolutionAPI',
|
'EvolutionAPI',
|
||||||
|
'https://evolution-api.com/files/evolution-api-favicon.png',
|
||||||
)) as any);
|
)) as any);
|
||||||
|
|
||||||
if (!contact) {
|
if (!contact) {
|
||||||
@@ -240,7 +232,6 @@ export class ChatwootService {
|
|||||||
data['status'] = 'pending';
|
data['status'] = 'pending';
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('this.provider', this.provider);
|
|
||||||
const conversation = await client.conversations.create({
|
const conversation = await client.conversations.create({
|
||||||
accountId: this.provider.account_id,
|
accountId: this.provider.account_id,
|
||||||
data,
|
data,
|
||||||
@@ -253,10 +244,10 @@ export class ChatwootService {
|
|||||||
|
|
||||||
this.logger.verbose('create message for init instance in chatwoot');
|
this.logger.verbose('create message for init instance in chatwoot');
|
||||||
|
|
||||||
let contentMsg = '/init';
|
let contentMsg = 'init';
|
||||||
|
|
||||||
if (number) {
|
if (number) {
|
||||||
contentMsg = `/init:${number}`;
|
contentMsg = `init:${number}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const message = await client.messages.create({
|
const message = await client.messages.create({
|
||||||
@@ -285,6 +276,7 @@ export class ChatwootService {
|
|||||||
isGroup: boolean,
|
isGroup: boolean,
|
||||||
name?: string,
|
name?: string,
|
||||||
avatar_url?: string,
|
avatar_url?: string,
|
||||||
|
jid?: string,
|
||||||
) {
|
) {
|
||||||
this.logger.verbose('create contact to instance: ' + instance.instanceName);
|
this.logger.verbose('create contact to instance: ' + instance.instanceName);
|
||||||
|
|
||||||
@@ -302,6 +294,7 @@ export class ChatwootService {
|
|||||||
inbox_id: inboxId,
|
inbox_id: inboxId,
|
||||||
name: name || phoneNumber,
|
name: name || phoneNumber,
|
||||||
phone_number: `+${phoneNumber}`,
|
phone_number: `+${phoneNumber}`,
|
||||||
|
identifier: jid,
|
||||||
avatar_url: avatar_url,
|
avatar_url: avatar_url,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
@@ -426,23 +419,18 @@ export class ChatwootService {
|
|||||||
|
|
||||||
if (isGroup) {
|
if (isGroup) {
|
||||||
this.logger.verbose('get group name');
|
this.logger.verbose('get group name');
|
||||||
const group = await this.waMonitor.waInstances[
|
const group = await this.waMonitor.waInstances[instance.instanceName].client.groupMetadata(chatId);
|
||||||
instance.instanceName
|
|
||||||
].client.groupMetadata(chatId);
|
|
||||||
|
|
||||||
nameContact = `${group.subject} (GROUP)`;
|
nameContact = `${group.subject} (GROUP)`;
|
||||||
|
|
||||||
this.logger.verbose('find or create participant in chatwoot');
|
this.logger.verbose('find or create participant in chatwoot');
|
||||||
|
|
||||||
const picture_url = await this.waMonitor.waInstances[
|
const picture_url = await this.waMonitor.waInstances[instance.instanceName].profilePicture(
|
||||||
instance.instanceName
|
|
||||||
].profilePicture(body.key.participant.split('@')[0]);
|
|
||||||
|
|
||||||
const findParticipant = await this.findContact(
|
|
||||||
instance,
|
|
||||||
body.key.participant.split('@')[0],
|
body.key.participant.split('@')[0],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const findParticipant = await this.findContact(instance, body.key.participant.split('@')[0]);
|
||||||
|
|
||||||
if (findParticipant) {
|
if (findParticipant) {
|
||||||
if (!findParticipant.name || findParticipant.name === chatId) {
|
if (!findParticipant.name || findParticipant.name === chatId) {
|
||||||
await this.updateContact(instance, findParticipant.id, {
|
await this.updateContact(instance, findParticipant.id, {
|
||||||
@@ -458,15 +446,14 @@ export class ChatwootService {
|
|||||||
false,
|
false,
|
||||||
body.pushName,
|
body.pushName,
|
||||||
picture_url.profilePictureUrl || null,
|
picture_url.profilePictureUrl || null,
|
||||||
|
body.key.participant,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.verbose('find or create contact in chatwoot');
|
this.logger.verbose('find or create contact in chatwoot');
|
||||||
|
|
||||||
const picture_url = await this.waMonitor.waInstances[
|
const picture_url = await this.waMonitor.waInstances[instance.instanceName].profilePicture(chatId);
|
||||||
instance.instanceName
|
|
||||||
].profilePicture(chatId);
|
|
||||||
|
|
||||||
const findContact = await this.findContact(instance, chatId);
|
const findContact = await this.findContact(instance, chatId);
|
||||||
|
|
||||||
@@ -475,6 +462,7 @@ export class ChatwootService {
|
|||||||
if (findContact) {
|
if (findContact) {
|
||||||
contact = findContact;
|
contact = findContact;
|
||||||
} else {
|
} else {
|
||||||
|
const jid = isGroup ? null : body.key.remoteJid;
|
||||||
contact = await this.createContact(
|
contact = await this.createContact(
|
||||||
instance,
|
instance,
|
||||||
chatId,
|
chatId,
|
||||||
@@ -482,6 +470,7 @@ export class ChatwootService {
|
|||||||
isGroup,
|
isGroup,
|
||||||
nameContact,
|
nameContact,
|
||||||
picture_url.profilePictureUrl || null,
|
picture_url.profilePictureUrl || null,
|
||||||
|
jid,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -495,6 +484,7 @@ export class ChatwootService {
|
|||||||
contact = findContact;
|
contact = findContact;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
const jid = isGroup ? null : body.key.remoteJid;
|
||||||
contact = await this.createContact(
|
contact = await this.createContact(
|
||||||
instance,
|
instance,
|
||||||
chatId,
|
chatId,
|
||||||
@@ -502,6 +492,7 @@ export class ChatwootService {
|
|||||||
isGroup,
|
isGroup,
|
||||||
nameContact,
|
nameContact,
|
||||||
picture_url.profilePictureUrl || null,
|
picture_url.profilePictureUrl || null,
|
||||||
|
jid,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -511,8 +502,7 @@ export class ChatwootService {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const contactId =
|
const contactId = contact?.payload?.id || contact?.payload?.contact?.id || contact?.id;
|
||||||
contact?.payload?.id || contact?.payload?.contact?.id || contact?.id;
|
|
||||||
|
|
||||||
if (!body.key.fromMe && contact.name === chatId && nameContact !== chatId) {
|
if (!body.key.fromMe && contact.name === chatId && nameContact !== chatId) {
|
||||||
this.logger.verbose('update contact name in chatwoot');
|
this.logger.verbose('update contact name in chatwoot');
|
||||||
@@ -530,14 +520,20 @@ export class ChatwootService {
|
|||||||
if (contactConversations) {
|
if (contactConversations) {
|
||||||
let conversation: any;
|
let conversation: any;
|
||||||
if (this.provider.reopen_conversation) {
|
if (this.provider.reopen_conversation) {
|
||||||
conversation = contactConversations.payload.find(
|
conversation = contactConversations.payload.find((conversation) => conversation.inbox_id == filterInbox.id);
|
||||||
(conversation) => conversation.inbox_id == filterInbox.id,
|
|
||||||
);
|
if (this.provider.conversation_pending) {
|
||||||
|
await client.conversations.toggleStatus({
|
||||||
|
accountId: this.provider.account_id,
|
||||||
|
conversationId: conversation.id,
|
||||||
|
data: {
|
||||||
|
status: 'pending',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
conversation = contactConversations.payload.find(
|
conversation = contactConversations.payload.find(
|
||||||
(conversation) =>
|
(conversation) => conversation.status !== 'resolved' && conversation.inbox_id == filterInbox.id,
|
||||||
conversation.status !== 'resolved' &&
|
|
||||||
conversation.inbox_id == filterInbox.id,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
this.logger.verbose('return conversation if exists');
|
this.logger.verbose('return conversation if exists');
|
||||||
@@ -596,9 +592,7 @@ export class ChatwootService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.logger.verbose('find inbox by name');
|
this.logger.verbose('find inbox by name');
|
||||||
const findByName = inbox.payload.find(
|
const findByName = inbox.payload.find((inbox) => inbox.name === instance.instanceName.split('-cwId-')[0]);
|
||||||
(inbox) => inbox.name === instance.instanceName,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!findByName) {
|
if (!findByName) {
|
||||||
this.logger.warn('inbox not found');
|
this.logger.warn('inbox not found');
|
||||||
@@ -700,8 +694,7 @@ export class ChatwootService {
|
|||||||
|
|
||||||
this.logger.verbose('find conversation by contact id');
|
this.logger.verbose('find conversation by contact id');
|
||||||
const conversation = findConversation.data.payload.find(
|
const conversation = findConversation.data.payload.find(
|
||||||
(conversation) =>
|
(conversation) => conversation?.meta?.sender?.id === contact.id && conversation.status === 'open',
|
||||||
conversation?.meta?.sender?.id === contact.id && conversation.status === 'open',
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!conversation) {
|
if (!conversation) {
|
||||||
@@ -821,8 +814,7 @@ export class ChatwootService {
|
|||||||
|
|
||||||
this.logger.verbose('find conversation by contact id');
|
this.logger.verbose('find conversation by contact id');
|
||||||
const conversation = findConversation.data.payload.find(
|
const conversation = findConversation.data.payload.find(
|
||||||
(conversation) =>
|
(conversation) => conversation?.meta?.sender?.id === contact.id && conversation.status === 'open',
|
||||||
conversation?.meta?.sender?.id === contact.id && conversation.status === 'open',
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!conversation) {
|
if (!conversation) {
|
||||||
@@ -872,12 +864,7 @@ export class ChatwootService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async sendAttachment(
|
public async sendAttachment(waInstance: any, number: string, media: any, caption?: string) {
|
||||||
waInstance: any,
|
|
||||||
number: string,
|
|
||||||
media: any,
|
|
||||||
caption?: string,
|
|
||||||
) {
|
|
||||||
this.logger.verbose('send attachment to instance: ' + waInstance.instanceName);
|
this.logger.verbose('send attachment to instance: ' + waInstance.instanceName);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -958,9 +945,7 @@ export class ChatwootService {
|
|||||||
|
|
||||||
public async receiveWebhook(instance: InstanceDto, body: any) {
|
public async receiveWebhook(instance: InstanceDto, body: any) {
|
||||||
try {
|
try {
|
||||||
this.logger.verbose(
|
this.logger.verbose('receive webhook to chatwoot instance: ' + instance.instanceName);
|
||||||
'receive webhook to chatwoot instance: ' + instance.instanceName,
|
|
||||||
);
|
|
||||||
const client = await this.clientCw(instance);
|
const client = await this.clientCw(instance);
|
||||||
|
|
||||||
if (!client) {
|
if (!client) {
|
||||||
@@ -969,12 +954,11 @@ export class ChatwootService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.logger.verbose('check if is bot');
|
this.logger.verbose('check if is bot');
|
||||||
if (!body?.conversation || body.private) return { message: 'bot' };
|
if (!body?.conversation || body.private || body.event === 'message_updated') return { message: 'bot' };
|
||||||
|
|
||||||
this.logger.verbose('check if is group');
|
this.logger.verbose('check if is group');
|
||||||
const chatId =
|
const chatId =
|
||||||
body.conversation.meta.sender?.phone_number?.replace('+', '') ||
|
body.conversation.meta.sender?.phone_number?.replace('+', '') || body.conversation.meta.sender?.identifier;
|
||||||
body.conversation.meta.sender?.identifier;
|
|
||||||
const messageReceived = body.content;
|
const messageReceived = body.content;
|
||||||
const senderName = body?.sender?.name;
|
const senderName = body?.sender?.name;
|
||||||
const waInstance = this.waMonitor.waInstances[instance.instanceName];
|
const waInstance = this.waMonitor.waInstances[instance.instanceName];
|
||||||
@@ -994,11 +978,7 @@ export class ChatwootService {
|
|||||||
await waInstance.connectToWhatsapp(number);
|
await waInstance.connectToWhatsapp(number);
|
||||||
} else {
|
} else {
|
||||||
this.logger.verbose('whatsapp already connected');
|
this.logger.verbose('whatsapp already connected');
|
||||||
await this.createBotMessage(
|
await this.createBotMessage(instance, `🚨 ${body.inbox.name} instance is connected.`, 'incoming');
|
||||||
instance,
|
|
||||||
`🚨 ${body.inbox.name} instance is connected.`,
|
|
||||||
'incoming',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1009,20 +989,12 @@ export class ChatwootService {
|
|||||||
|
|
||||||
if (!state) {
|
if (!state) {
|
||||||
this.logger.verbose('state not found');
|
this.logger.verbose('state not found');
|
||||||
await this.createBotMessage(
|
await this.createBotMessage(instance, `⚠️ ${body.inbox.name} instance not found.`, 'incoming');
|
||||||
instance,
|
|
||||||
`⚠️ ${body.inbox.name} instance not found.`,
|
|
||||||
'incoming',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state) {
|
if (state) {
|
||||||
this.logger.verbose('state: ' + state + ' found');
|
this.logger.verbose('state: ' + state + ' found');
|
||||||
await this.createBotMessage(
|
await this.createBotMessage(instance, `⚠️ ${body.inbox.name} instance status: *${state}*`, 'incoming');
|
||||||
instance,
|
|
||||||
`⚠️ ${body.inbox.name} instance status: *${state}*`,
|
|
||||||
'incoming',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1038,52 +1010,12 @@ export class ChatwootService {
|
|||||||
await waInstance?.client?.logout('Log out instance: ' + instance.instanceName);
|
await waInstance?.client?.logout('Log out instance: ' + instance.instanceName);
|
||||||
await waInstance?.client?.ws?.close();
|
await waInstance?.client?.ws?.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (command.includes('new_instance')) {
|
|
||||||
const urlServer = this.configService.get<HttpServer>('SERVER').URL;
|
|
||||||
const apiKey = this.configService.get('AUTHENTICATION').API_KEY.KEY;
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
instanceName: command.split(':')[1],
|
|
||||||
qrcode: true,
|
|
||||||
chatwoot_account_id: this.provider.account_id,
|
|
||||||
chatwoot_token: this.provider.token,
|
|
||||||
chatwoot_url: this.provider.url,
|
|
||||||
chatwoot_sign_msg: this.provider.sign_msg,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (command.split(':')[2]) {
|
|
||||||
data['number'] = command.split(':')[2];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const config = {
|
if (body.message_type === 'outgoing' && body?.conversation?.messages?.length && chatId !== '123456') {
|
||||||
method: 'post',
|
|
||||||
maxBodyLength: Infinity,
|
|
||||||
url: `${urlServer}/instance/create`,
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
apikey: apiKey,
|
|
||||||
},
|
|
||||||
data: data,
|
|
||||||
};
|
|
||||||
|
|
||||||
await axios.request(config);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
body.message_type === 'outgoing' &&
|
|
||||||
body?.conversation?.messages?.length &&
|
|
||||||
chatId !== '123456'
|
|
||||||
) {
|
|
||||||
this.logger.verbose('check if is group');
|
this.logger.verbose('check if is group');
|
||||||
|
|
||||||
this.messageCacheFile = path.join(
|
this.messageCacheFile = path.join(ROOT_DIR, 'store', 'chatwoot', `${instance.instanceName}_cache.txt`);
|
||||||
ROOT_DIR,
|
|
||||||
'store',
|
|
||||||
'chatwoot',
|
|
||||||
`${instance.instanceName}_cache.txt`,
|
|
||||||
);
|
|
||||||
this.logger.verbose('cache file path: ' + this.messageCacheFile);
|
this.logger.verbose('cache file path: ' + this.messageCacheFile);
|
||||||
|
|
||||||
this.messageCache = this.loadMessageCache();
|
this.messageCache = this.loadMessageCache();
|
||||||
@@ -1104,9 +1036,7 @@ export class ChatwootService {
|
|||||||
if (senderName === null || senderName === undefined) {
|
if (senderName === null || senderName === undefined) {
|
||||||
formatText = messageReceived;
|
formatText = messageReceived;
|
||||||
} else {
|
} else {
|
||||||
formatText = this.provider.sign_msg
|
formatText = this.provider.sign_msg ? `*${senderName}:*\n${messageReceived}` : messageReceived;
|
||||||
? `*${senderName}:*\n\n${messageReceived}`
|
|
||||||
: messageReceived;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const message of body.conversation.messages) {
|
for (const message of body.conversation.messages) {
|
||||||
@@ -1120,12 +1050,7 @@ export class ChatwootService {
|
|||||||
formatText = null;
|
formatText = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.sendAttachment(
|
await this.sendAttachment(waInstance, chatId, attachment.data_url, formatText);
|
||||||
waInstance,
|
|
||||||
chatId,
|
|
||||||
attachment.data_url,
|
|
||||||
formatText,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.logger.verbose('message is text');
|
this.logger.verbose('message is text');
|
||||||
@@ -1204,16 +1129,12 @@ export class ChatwootService {
|
|||||||
messageContextInfo: msg.messageContextInfo?.stanzaId,
|
messageContextInfo: msg.messageContextInfo?.stanzaId,
|
||||||
stickerMessage: undefined,
|
stickerMessage: undefined,
|
||||||
documentMessage: msg.documentMessage?.caption,
|
documentMessage: msg.documentMessage?.caption,
|
||||||
documentWithCaptionMessage:
|
documentWithCaptionMessage: msg.documentWithCaptionMessage?.message?.documentMessage?.caption,
|
||||||
msg.documentWithCaptionMessage?.message?.documentMessage?.caption,
|
|
||||||
audioMessage: msg.audioMessage?.caption,
|
audioMessage: msg.audioMessage?.caption,
|
||||||
contactMessage: msg.contactMessage?.vcard,
|
contactMessage: msg.contactMessage?.vcard,
|
||||||
contactsArrayMessage: msg.contactsArrayMessage,
|
contactsArrayMessage: msg.contactsArrayMessage,
|
||||||
locationMessage: msg.locationMessage
|
locationMessage: msg.locationMessage,
|
||||||
? msg.locationMessage?.degreesLatitude +
|
liveLocationMessage: msg.liveLocationMessage,
|
||||||
',' +
|
|
||||||
msg.locationMessage?.degreesLongitude
|
|
||||||
: undefined,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.logger.verbose('type message: ' + types);
|
this.logger.verbose('type message: ' + types);
|
||||||
@@ -1227,8 +1148,9 @@ export class ChatwootService {
|
|||||||
|
|
||||||
const result = typeKey ? types[typeKey] : undefined;
|
const result = typeKey ? types[typeKey] : undefined;
|
||||||
|
|
||||||
if (typeKey === 'locationMessage') {
|
if (typeKey === 'locationMessage' || typeKey === 'liveLocationMessage') {
|
||||||
const [latitude, longitude] = result.split(',');
|
const latitude = result.degreesLatitude;
|
||||||
|
const longitude = result.degreesLongitude;
|
||||||
|
|
||||||
const formattedLocation = `**Location:**
|
const formattedLocation = `**Location:**
|
||||||
**latitude:** ${latitude}
|
**latitude:** ${latitude}
|
||||||
@@ -1401,31 +1323,21 @@ export class ChatwootService {
|
|||||||
|
|
||||||
if (!body.key.fromMe) {
|
if (!body.key.fromMe) {
|
||||||
this.logger.verbose('message is not from me');
|
this.logger.verbose('message is not from me');
|
||||||
content = `**${participantName}**\n\n${bodyMessage}`;
|
content = `**${participantName}:**\n\n${bodyMessage}`;
|
||||||
} else {
|
} else {
|
||||||
this.logger.verbose('message is from me');
|
this.logger.verbose('message is from me');
|
||||||
content = `${bodyMessage}`;
|
content = `${bodyMessage}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.verbose('send data to chatwoot');
|
this.logger.verbose('send data to chatwoot');
|
||||||
const send = await this.sendData(
|
const send = await this.sendData(getConversion, fileName, messageType, content);
|
||||||
getConversion,
|
|
||||||
fileName,
|
|
||||||
messageType,
|
|
||||||
content,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!send) {
|
if (!send) {
|
||||||
this.logger.warn('message not sent');
|
this.logger.warn('message not sent');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.messageCacheFile = path.join(
|
this.messageCacheFile = path.join(ROOT_DIR, 'store', 'chatwoot', `${instance.instanceName}_cache.txt`);
|
||||||
ROOT_DIR,
|
|
||||||
'store',
|
|
||||||
'chatwoot',
|
|
||||||
`${instance.instanceName}_cache.txt`,
|
|
||||||
);
|
|
||||||
|
|
||||||
this.messageCache = this.loadMessageCache();
|
this.messageCache = this.loadMessageCache();
|
||||||
|
|
||||||
@@ -1439,24 +1351,14 @@ export class ChatwootService {
|
|||||||
this.logger.verbose('message is not group');
|
this.logger.verbose('message is not group');
|
||||||
|
|
||||||
this.logger.verbose('send data to chatwoot');
|
this.logger.verbose('send data to chatwoot');
|
||||||
const send = await this.sendData(
|
const send = await this.sendData(getConversion, fileName, messageType, bodyMessage);
|
||||||
getConversion,
|
|
||||||
fileName,
|
|
||||||
messageType,
|
|
||||||
bodyMessage,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!send) {
|
if (!send) {
|
||||||
this.logger.warn('message not sent');
|
this.logger.warn('message not sent');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.messageCacheFile = path.join(
|
this.messageCacheFile = path.join(ROOT_DIR, 'store', 'chatwoot', `${instance.instanceName}_cache.txt`);
|
||||||
ROOT_DIR,
|
|
||||||
'store',
|
|
||||||
'chatwoot',
|
|
||||||
`${instance.instanceName}_cache.txt`,
|
|
||||||
);
|
|
||||||
|
|
||||||
this.messageCache = this.loadMessageCache();
|
this.messageCache = this.loadMessageCache();
|
||||||
|
|
||||||
@@ -1485,24 +1387,14 @@ export class ChatwootService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.logger.verbose('send data to chatwoot');
|
this.logger.verbose('send data to chatwoot');
|
||||||
const send = await this.createMessage(
|
const send = await this.createMessage(instance, getConversion, content, messageType);
|
||||||
instance,
|
|
||||||
getConversion,
|
|
||||||
content,
|
|
||||||
messageType,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!send) {
|
if (!send) {
|
||||||
this.logger.warn('message not sent');
|
this.logger.warn('message not sent');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.messageCacheFile = path.join(
|
this.messageCacheFile = path.join(ROOT_DIR, 'store', 'chatwoot', `${instance.instanceName}_cache.txt`);
|
||||||
ROOT_DIR,
|
|
||||||
'store',
|
|
||||||
'chatwoot',
|
|
||||||
`${instance.instanceName}_cache.txt`,
|
|
||||||
);
|
|
||||||
|
|
||||||
this.messageCache = this.loadMessageCache();
|
this.messageCache = this.loadMessageCache();
|
||||||
|
|
||||||
@@ -1516,24 +1408,14 @@ export class ChatwootService {
|
|||||||
this.logger.verbose('message is not group');
|
this.logger.verbose('message is not group');
|
||||||
|
|
||||||
this.logger.verbose('send data to chatwoot');
|
this.logger.verbose('send data to chatwoot');
|
||||||
const send = await this.createMessage(
|
const send = await this.createMessage(instance, getConversion, bodyMessage, messageType);
|
||||||
instance,
|
|
||||||
getConversion,
|
|
||||||
bodyMessage,
|
|
||||||
messageType,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!send) {
|
if (!send) {
|
||||||
this.logger.warn('message not sent');
|
this.logger.warn('message not sent');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.messageCacheFile = path.join(
|
this.messageCacheFile = path.join(ROOT_DIR, 'store', 'chatwoot', `${instance.instanceName}_cache.txt`);
|
||||||
ROOT_DIR,
|
|
||||||
'store',
|
|
||||||
'chatwoot',
|
|
||||||
`${instance.instanceName}_cache.txt`,
|
|
||||||
);
|
|
||||||
|
|
||||||
this.messageCache = this.loadMessageCache();
|
this.messageCache = this.loadMessageCache();
|
||||||
|
|
||||||
@@ -1577,22 +1459,15 @@ export class ChatwootService {
|
|||||||
this.logger.verbose('event qrcode.updated');
|
this.logger.verbose('event qrcode.updated');
|
||||||
if (body.statusCode === 500) {
|
if (body.statusCode === 500) {
|
||||||
this.logger.verbose('qrcode error');
|
this.logger.verbose('qrcode error');
|
||||||
const erroQRcode = `🚨 QRCode generation limit reached, to generate a new QRCode, send the /init message again.`;
|
const erroQRcode = `🚨 QRCode generation limit reached, to generate a new QRCode, send the 'init' message again.`;
|
||||||
|
|
||||||
this.logger.verbose('send message to chatwoot');
|
this.logger.verbose('send message to chatwoot');
|
||||||
return await this.createBotMessage(instance, erroQRcode, 'incoming');
|
return await this.createBotMessage(instance, erroQRcode, 'incoming');
|
||||||
} else {
|
} else {
|
||||||
this.logger.verbose('qrcode success');
|
this.logger.verbose('qrcode success');
|
||||||
const fileData = Buffer.from(
|
const fileData = Buffer.from(body?.qrcode.base64.replace('data:image/png;base64,', ''), 'base64');
|
||||||
body?.qrcode.base64.replace('data:image/png;base64,', ''),
|
|
||||||
'base64',
|
|
||||||
);
|
|
||||||
|
|
||||||
const fileName = `${path.join(
|
const fileName = `${path.join(waInstance?.storePath, 'temp', `${`${instance}.png`}`)}`;
|
||||||
waInstance?.storePath,
|
|
||||||
'temp',
|
|
||||||
`${`${instance}.png`}`,
|
|
||||||
)}`;
|
|
||||||
|
|
||||||
this.logger.verbose('temp file name: ' + fileName);
|
this.logger.verbose('temp file name: ' + fileName);
|
||||||
|
|
||||||
@@ -1600,22 +1475,17 @@ export class ChatwootService {
|
|||||||
writeFileSync(fileName, fileData, 'utf8');
|
writeFileSync(fileName, fileData, 'utf8');
|
||||||
|
|
||||||
this.logger.verbose('send qrcode to chatwoot');
|
this.logger.verbose('send qrcode to chatwoot');
|
||||||
await this.createBotQr(
|
await this.createBotQr(instance, 'QRCode successfully generated!', 'incoming', fileName);
|
||||||
instance,
|
|
||||||
'QRCode successfully generated!',
|
|
||||||
'incoming',
|
|
||||||
fileName,
|
|
||||||
);
|
|
||||||
|
|
||||||
let msgQrCode = `⚡️ QRCode successfully generated!\n\nScan this QR code within the next 40 seconds.`;
|
let msgQrCode = `⚡️ QRCode successfully generated!\n\nScan this QR code within the next 40 seconds.`;
|
||||||
|
|
||||||
if (body?.qrcode?.pairingCode) {
|
if (body?.qrcode?.pairingCode) {
|
||||||
msgQrCode =
|
msgQrCode =
|
||||||
msgQrCode +
|
msgQrCode +
|
||||||
`\n\n*Pairing Code:* ${body.qrcode.pairingCode.substring(
|
`\n\n*Pairing Code:* ${body.qrcode.pairingCode.substring(0, 4)}-${body.qrcode.pairingCode.substring(
|
||||||
0,
|
|
||||||
4,
|
4,
|
||||||
)}-${body.qrcode.pairingCode.substring(4, 8)}`;
|
8,
|
||||||
|
)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.verbose('send message to chatwoot');
|
this.logger.verbose('send message to chatwoot');
|
||||||
@@ -1626,49 +1496,4 @@ export class ChatwootService {
|
|||||||
this.logger.error(error);
|
this.logger.error(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async newInstance(data: any) {
|
|
||||||
try {
|
|
||||||
const instanceName = data.instanceName;
|
|
||||||
const qrcode = true;
|
|
||||||
const number = data.number;
|
|
||||||
const accountId = data.accountId;
|
|
||||||
const chatwootToken = data.token;
|
|
||||||
const chatwootUrl = data.url;
|
|
||||||
const signMsg = true;
|
|
||||||
const urlServer = this.configService.get<HttpServer>('SERVER').URL;
|
|
||||||
const apiKey = this.configService.get('AUTHENTICATION').API_KEY.KEY;
|
|
||||||
|
|
||||||
const requestData = {
|
|
||||||
instanceName,
|
|
||||||
qrcode,
|
|
||||||
chatwoot_account_id: accountId,
|
|
||||||
chatwoot_token: chatwootToken,
|
|
||||||
chatwoot_url: chatwootUrl,
|
|
||||||
chatwoot_sign_msg: signMsg,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (number) {
|
|
||||||
requestData['number'] = number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const config = {
|
|
||||||
method: 'post',
|
|
||||||
maxBodyLength: Infinity,
|
|
||||||
url: `${urlServer}/instance/create`,
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
apikey: apiKey,
|
|
||||||
},
|
|
||||||
data: requestData,
|
|
||||||
};
|
|
||||||
|
|
||||||
// await axios.request(config);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (error) {
|
|
||||||
this.logger.error(error);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,15 @@
|
|||||||
import { opendirSync, readdirSync, rmSync } from 'fs';
|
|
||||||
import { WAStartupService } from './whatsapp.service';
|
|
||||||
import { INSTANCE_DIR, STORE_DIR } from '../../config/path.config';
|
|
||||||
import EventEmitter2 from 'eventemitter2';
|
|
||||||
import { join } from 'path';
|
|
||||||
import { Logger } from '../../config/logger.config';
|
|
||||||
import {
|
|
||||||
Auth,
|
|
||||||
ConfigService,
|
|
||||||
Database,
|
|
||||||
DelInstance,
|
|
||||||
HttpServer,
|
|
||||||
Redis,
|
|
||||||
} from '../../config/env.config';
|
|
||||||
import { RepositoryBroker } from '../repository/repository.manager';
|
|
||||||
import { NotFoundException } from '../../exceptions';
|
|
||||||
import { Db } from 'mongodb';
|
|
||||||
import { RedisCache } from '../../db/redis.client';
|
|
||||||
import { execSync } from 'child_process';
|
import { execSync } from 'child_process';
|
||||||
import { dbserver } from '../../db/db.connect';
|
import EventEmitter2 from 'eventemitter2';
|
||||||
import mongoose from 'mongoose';
|
import { opendirSync, readdirSync, rmSync } from 'fs';
|
||||||
|
import { Db } from 'mongodb';
|
||||||
|
import { join } from 'path';
|
||||||
|
|
||||||
|
import { Auth, ConfigService, Database, DelInstance, HttpServer, Redis } from '../../config/env.config';
|
||||||
|
import { Logger } from '../../config/logger.config';
|
||||||
|
import { INSTANCE_DIR, STORE_DIR } from '../../config/path.config';
|
||||||
|
import { NotFoundException } from '../../exceptions';
|
||||||
|
import { dbserver } from '../../libs/db.connect';
|
||||||
|
import { RedisCache } from '../../libs/redis.client';
|
||||||
import {
|
import {
|
||||||
AuthModel,
|
AuthModel,
|
||||||
ChatwootModel,
|
ChatwootModel,
|
||||||
@@ -28,6 +19,8 @@ import {
|
|||||||
SettingsModel,
|
SettingsModel,
|
||||||
WebhookModel,
|
WebhookModel,
|
||||||
} from '../models';
|
} from '../models';
|
||||||
|
import { RepositoryBroker } from '../repository/repository.manager';
|
||||||
|
import { WAStartupService } from './whatsapp.service';
|
||||||
|
|
||||||
export class WAMonitoringService {
|
export class WAMonitoringService {
|
||||||
constructor(
|
constructor(
|
||||||
@@ -63,16 +56,12 @@ export class WAMonitoringService {
|
|||||||
public delInstanceTime(instance: string) {
|
public delInstanceTime(instance: string) {
|
||||||
const time = this.configService.get<DelInstance>('DEL_INSTANCE');
|
const time = this.configService.get<DelInstance>('DEL_INSTANCE');
|
||||||
if (typeof time === 'number' && time > 0) {
|
if (typeof time === 'number' && time > 0) {
|
||||||
this.logger.verbose(
|
this.logger.verbose(`Instance "${instance}" don't have connection, will be removed in ${time} minutes`);
|
||||||
`Instance "${instance}" don't have connection, will be removed in ${time} minutes`,
|
|
||||||
);
|
|
||||||
|
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
if (this.waInstances[instance]?.connectionStatus?.state !== 'open') {
|
if (this.waInstances[instance]?.connectionStatus?.state !== 'open') {
|
||||||
if (this.waInstances[instance]?.connectionStatus?.state === 'connecting') {
|
if (this.waInstances[instance]?.connectionStatus?.state === 'connecting') {
|
||||||
await this.waInstances[instance]?.client?.logout(
|
await this.waInstances[instance]?.client?.logout('Log out instance: ' + instance);
|
||||||
'Log out instance: ' + instance,
|
|
||||||
);
|
|
||||||
this.waInstances[instance]?.client?.ws?.close();
|
this.waInstances[instance]?.client?.ws?.close();
|
||||||
this.waInstances[instance]?.client?.end(undefined);
|
this.waInstances[instance]?.client?.end(undefined);
|
||||||
delete this.waInstances[instance];
|
delete this.waInstances[instance];
|
||||||
@@ -105,7 +94,7 @@ export class WAMonitoringService {
|
|||||||
if (findChatwoot && findChatwoot.enabled) {
|
if (findChatwoot && findChatwoot.enabled) {
|
||||||
chatwoot = {
|
chatwoot = {
|
||||||
...findChatwoot,
|
...findChatwoot,
|
||||||
webhook_url: `${urlServer}/chatwoot/webhook/${key}`,
|
webhook_url: `${urlServer}/chatwoot/webhook/${encodeURIComponent(key)}`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,21 +113,16 @@ export class WAMonitoringService {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (this.configService.get<Auth>('AUTHENTICATION').EXPOSE_IN_FETCH_INSTANCES) {
|
if (this.configService.get<Auth>('AUTHENTICATION').EXPOSE_IN_FETCH_INSTANCES) {
|
||||||
instanceData.instance['serverUrl'] =
|
instanceData.instance['serverUrl'] = this.configService.get<HttpServer>('SERVER').URL;
|
||||||
this.configService.get<HttpServer>('SERVER').URL;
|
|
||||||
|
|
||||||
instanceData.instance['apikey'] = (
|
instanceData.instance['apikey'] = (await this.repository.auth.find(key)).apikey;
|
||||||
await this.repository.auth.find(key)
|
|
||||||
).apikey;
|
|
||||||
|
|
||||||
instanceData.instance['chatwoot'] = chatwoot;
|
instanceData.instance['chatwoot'] = chatwoot;
|
||||||
}
|
}
|
||||||
|
|
||||||
instances.push(instanceData);
|
instances.push(instanceData);
|
||||||
} else {
|
} else {
|
||||||
this.logger.verbose(
|
this.logger.verbose('instance: ' + key + ' - connectionStatus: ' + value.connectionStatus.state);
|
||||||
'instance: ' + key + ' - connectionStatus: ' + value.connectionStatus.state,
|
|
||||||
);
|
|
||||||
|
|
||||||
const instanceData = {
|
const instanceData = {
|
||||||
instance: {
|
instance: {
|
||||||
@@ -148,12 +132,9 @@ export class WAMonitoringService {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (this.configService.get<Auth>('AUTHENTICATION').EXPOSE_IN_FETCH_INSTANCES) {
|
if (this.configService.get<Auth>('AUTHENTICATION').EXPOSE_IN_FETCH_INSTANCES) {
|
||||||
instanceData.instance['serverUrl'] =
|
instanceData.instance['serverUrl'] = this.configService.get<HttpServer>('SERVER').URL;
|
||||||
this.configService.get<HttpServer>('SERVER').URL;
|
|
||||||
|
|
||||||
instanceData.instance['apikey'] = (
|
instanceData.instance['apikey'] = (await this.repository.auth.find(key)).apikey;
|
||||||
await this.repository.auth.find(key)
|
|
||||||
).apikey;
|
|
||||||
|
|
||||||
instanceData.instance['chatwoot'] = chatwoot;
|
instanceData.instance['chatwoot'] = chatwoot;
|
||||||
}
|
}
|
||||||
@@ -176,14 +157,11 @@ export class WAMonitoringService {
|
|||||||
collections.forEach(async (collection) => {
|
collections.forEach(async (collection) => {
|
||||||
const name = collection.namespace.replace(/^[\w-]+./, '');
|
const name = collection.namespace.replace(/^[\w-]+./, '');
|
||||||
await this.dbInstance.collection(name).deleteMany({
|
await this.dbInstance.collection(name).deleteMany({
|
||||||
$or: [
|
$or: [{ _id: { $regex: /^app.state.*/ } }, { _id: { $regex: /^session-.*/ } }],
|
||||||
{ _id: { $regex: /^app.state.*/ } },
|
|
||||||
{ _id: { $regex: /^session-.*/ } },
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
this.logger.verbose('instance files deleted: ' + name);
|
this.logger.verbose('instance files deleted: ' + name);
|
||||||
});
|
});
|
||||||
} else if (this.redis.ENABLED) {
|
// } else if (this.redis.ENABLED) {
|
||||||
} else {
|
} else {
|
||||||
const dir = opendirSync(INSTANCE_DIR, { encoding: 'utf-8' });
|
const dir = opendirSync(INSTANCE_DIR, { encoding: 'utf-8' });
|
||||||
for await (const dirent of dir) {
|
for await (const dirent of dir) {
|
||||||
@@ -264,12 +242,7 @@ export class WAMonitoringService {
|
|||||||
public async loadInstance() {
|
public async loadInstance() {
|
||||||
this.logger.verbose('load instances');
|
this.logger.verbose('load instances');
|
||||||
const set = async (name: string) => {
|
const set = async (name: string) => {
|
||||||
const instance = new WAStartupService(
|
const instance = new WAStartupService(this.configService, this.eventEmitter, this.repository, this.cache);
|
||||||
this.configService,
|
|
||||||
this.eventEmitter,
|
|
||||||
this.repository,
|
|
||||||
this.cache,
|
|
||||||
);
|
|
||||||
instance.instanceName = name;
|
instance.instanceName = name;
|
||||||
this.logger.verbose('instance loaded: ' + name);
|
this.logger.verbose('instance loaded: ' + name);
|
||||||
|
|
||||||
@@ -299,9 +272,7 @@ export class WAMonitoringService {
|
|||||||
const collections: any[] = await this.dbInstance.collections();
|
const collections: any[] = await this.dbInstance.collections();
|
||||||
if (collections.length > 0) {
|
if (collections.length > 0) {
|
||||||
this.logger.verbose('reading collections and setting instances');
|
this.logger.verbose('reading collections and setting instances');
|
||||||
collections.forEach(
|
collections.forEach(async (coll) => await set(coll.namespace.replace(/^[\w-]+\./, '')));
|
||||||
async (coll) => await set(coll.namespace.replace(/^[\w-]+\./, '')),
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
this.logger.verbose('no collections found');
|
this.logger.verbose('no collections found');
|
||||||
}
|
}
|
||||||
@@ -337,7 +308,9 @@ export class WAMonitoringService {
|
|||||||
try {
|
try {
|
||||||
this.logger.verbose('instance: ' + instanceName + ' - removing from memory');
|
this.logger.verbose('instance: ' + instanceName + ' - removing from memory');
|
||||||
this.waInstances[instanceName] = undefined;
|
this.waInstances[instanceName] = undefined;
|
||||||
} catch {}
|
} catch (error) {
|
||||||
|
this.logger.error(error);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.logger.verbose('request cleaning up instance: ' + instanceName);
|
this.logger.verbose('request cleaning up instance: ' + instanceName);
|
||||||
@@ -362,11 +335,14 @@ export class WAMonitoringService {
|
|||||||
this.logger.verbose('checking instances without connection');
|
this.logger.verbose('checking instances without connection');
|
||||||
this.eventEmitter.on('no.connection', async (instanceName) => {
|
this.eventEmitter.on('no.connection', async (instanceName) => {
|
||||||
try {
|
try {
|
||||||
this.logger.verbose('instance: ' + instanceName + ' - removing from memory');
|
this.logger.verbose('logging out instance: ' + instanceName);
|
||||||
this.waInstances[instanceName] = undefined;
|
await this.waInstances[instanceName]?.client?.logout('Log out instance: ' + instanceName);
|
||||||
|
|
||||||
this.logger.verbose('request cleaning up instance: ' + instanceName);
|
this.logger.verbose('close connection instance: ' + instanceName);
|
||||||
this.cleaningUp(instanceName);
|
this.waInstances[instanceName]?.client?.ws?.close();
|
||||||
|
|
||||||
|
this.waInstances[instanceName].instance.qrcode = { count: 0 };
|
||||||
|
this.waInstances[instanceName].stateConnection.state = 'close';
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.error({
|
this.logger.error({
|
||||||
localError: 'noConnection',
|
localError: 'noConnection',
|
||||||
|
|||||||
33
src/whatsapp/services/proxy.service.ts
Normal file
33
src/whatsapp/services/proxy.service.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { Logger } from '../../config/logger.config';
|
||||||
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
|
import { ProxyDto } from '../dto/proxy.dto';
|
||||||
|
import { ProxyRaw } from '../models';
|
||||||
|
import { WAMonitoringService } from './monitor.service';
|
||||||
|
|
||||||
|
export class ProxyService {
|
||||||
|
constructor(private readonly waMonitor: WAMonitoringService) {}
|
||||||
|
|
||||||
|
private readonly logger = new Logger(ProxyService.name);
|
||||||
|
|
||||||
|
public create(instance: InstanceDto, data: ProxyDto) {
|
||||||
|
this.logger.verbose('create proxy: ' + instance.instanceName);
|
||||||
|
this.waMonitor.waInstances[instance.instanceName].setProxy(data);
|
||||||
|
|
||||||
|
return { proxy: { ...instance, proxy: data } };
|
||||||
|
}
|
||||||
|
|
||||||
|
public async find(instance: InstanceDto): Promise<ProxyRaw> {
|
||||||
|
try {
|
||||||
|
this.logger.verbose('find proxy: ' + instance.instanceName);
|
||||||
|
const result = await this.waMonitor.waInstances[instance.instanceName].findProxy();
|
||||||
|
|
||||||
|
if (Object.keys(result).length === 0) {
|
||||||
|
throw new Error('Proxy not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
return { enabled: false, proxy: '' };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
33
src/whatsapp/services/rabbitmq.service.ts
Normal file
33
src/whatsapp/services/rabbitmq.service.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { Logger } from '../../config/logger.config';
|
||||||
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
|
import { RabbitmqDto } from '../dto/rabbitmq.dto';
|
||||||
|
import { RabbitmqRaw } from '../models';
|
||||||
|
import { WAMonitoringService } from './monitor.service';
|
||||||
|
|
||||||
|
export class RabbitmqService {
|
||||||
|
constructor(private readonly waMonitor: WAMonitoringService) {}
|
||||||
|
|
||||||
|
private readonly logger = new Logger(RabbitmqService.name);
|
||||||
|
|
||||||
|
public create(instance: InstanceDto, data: RabbitmqDto) {
|
||||||
|
this.logger.verbose('create rabbitmq: ' + instance.instanceName);
|
||||||
|
this.waMonitor.waInstances[instance.instanceName].setRabbitmq(data);
|
||||||
|
|
||||||
|
return { rabbitmq: { ...instance, rabbitmq: data } };
|
||||||
|
}
|
||||||
|
|
||||||
|
public async find(instance: InstanceDto): Promise<RabbitmqRaw> {
|
||||||
|
try {
|
||||||
|
this.logger.verbose('find rabbitmq: ' + instance.instanceName);
|
||||||
|
const result = await this.waMonitor.waInstances[instance.instanceName].findRabbitmq();
|
||||||
|
|
||||||
|
if (Object.keys(result).length === 0) {
|
||||||
|
throw new Error('Rabbitmq not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
return { enabled: false, events: [] };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
|
import { Logger } from '../../config/logger.config';
|
||||||
import { InstanceDto } from '../dto/instance.dto';
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
import { SettingsDto } from '../dto/settings.dto';
|
import { SettingsDto } from '../dto/settings.dto';
|
||||||
import { WAMonitoringService } from './monitor.service';
|
import { WAMonitoringService } from './monitor.service';
|
||||||
import { Logger } from '../../config/logger.config';
|
|
||||||
|
|
||||||
export class SettingsService {
|
export class SettingsService {
|
||||||
constructor(private readonly waMonitor: WAMonitoringService) {}
|
constructor(private readonly waMonitor: WAMonitoringService) {}
|
||||||
@@ -18,9 +18,7 @@ export class SettingsService {
|
|||||||
public async find(instance: InstanceDto): Promise<SettingsDto> {
|
public async find(instance: InstanceDto): Promise<SettingsDto> {
|
||||||
try {
|
try {
|
||||||
this.logger.verbose('find settings: ' + instance.instanceName);
|
this.logger.verbose('find settings: ' + instance.instanceName);
|
||||||
const result = await this.waMonitor.waInstances[
|
const result = await this.waMonitor.waInstances[instance.instanceName].findSettings();
|
||||||
instance.instanceName
|
|
||||||
].findSettings();
|
|
||||||
|
|
||||||
if (Object.keys(result).length === 0) {
|
if (Object.keys(result).length === 0) {
|
||||||
throw new Error('Settings not found');
|
throw new Error('Settings not found');
|
||||||
|
|||||||
490
src/whatsapp/services/typebot.service.ts
Normal file
490
src/whatsapp/services/typebot.service.ts
Normal file
@@ -0,0 +1,490 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
import { Logger } from '../../config/logger.config';
|
||||||
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
|
import { Session, TypebotDto } from '../dto/typebot.dto';
|
||||||
|
import { MessageRaw } from '../models';
|
||||||
|
import { WAMonitoringService } from './monitor.service';
|
||||||
|
|
||||||
|
export class TypebotService {
|
||||||
|
constructor(private readonly waMonitor: WAMonitoringService) {}
|
||||||
|
|
||||||
|
private readonly logger = new Logger(TypebotService.name);
|
||||||
|
|
||||||
|
public create(instance: InstanceDto, data: TypebotDto) {
|
||||||
|
this.logger.verbose('create typebot: ' + instance.instanceName);
|
||||||
|
this.waMonitor.waInstances[instance.instanceName].setTypebot(data);
|
||||||
|
|
||||||
|
return { typebot: { ...instance, typebot: data } };
|
||||||
|
}
|
||||||
|
|
||||||
|
public async find(instance: InstanceDto): Promise<TypebotDto> {
|
||||||
|
try {
|
||||||
|
this.logger.verbose('find typebot: ' + instance.instanceName);
|
||||||
|
const result = await this.waMonitor.waInstances[instance.instanceName].findTypebot();
|
||||||
|
|
||||||
|
if (Object.keys(result).length === 0) {
|
||||||
|
throw new Error('Typebot not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
return { enabled: false, url: '', typebot: '', expire: 0, sessions: [] };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async changeStatus(instance: InstanceDto, data: any) {
|
||||||
|
const remoteJid = data.remoteJid;
|
||||||
|
const status = data.status;
|
||||||
|
|
||||||
|
const findData = await this.find(instance);
|
||||||
|
|
||||||
|
const session = findData.sessions.find((session) => session.remoteJid === remoteJid);
|
||||||
|
|
||||||
|
if (session) {
|
||||||
|
if (status === 'closed') {
|
||||||
|
findData.sessions.splice(findData.sessions.indexOf(session), 1);
|
||||||
|
|
||||||
|
const typebotData = {
|
||||||
|
enabled: true,
|
||||||
|
url: findData.url,
|
||||||
|
typebot: findData.typebot,
|
||||||
|
expire: findData.expire,
|
||||||
|
keyword_finish: findData.keyword_finish,
|
||||||
|
delay_message: findData.delay_message,
|
||||||
|
unknown_message: findData.unknown_message,
|
||||||
|
sessions: findData.sessions,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.create(instance, typebotData);
|
||||||
|
|
||||||
|
return { typebot: { ...instance, typebot: typebotData } };
|
||||||
|
}
|
||||||
|
|
||||||
|
findData.sessions.map((session) => {
|
||||||
|
if (session.remoteJid === remoteJid) {
|
||||||
|
session.status = status;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const typebotData = {
|
||||||
|
enabled: true,
|
||||||
|
url: findData.url,
|
||||||
|
typebot: findData.typebot,
|
||||||
|
expire: findData.expire,
|
||||||
|
keyword_finish: findData.keyword_finish,
|
||||||
|
delay_message: findData.delay_message,
|
||||||
|
unknown_message: findData.unknown_message,
|
||||||
|
sessions: findData.sessions,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.create(instance, typebotData);
|
||||||
|
|
||||||
|
return { typebot: { ...instance, typebot: typebotData } };
|
||||||
|
}
|
||||||
|
|
||||||
|
public async startTypebot(instance: InstanceDto, data: any) {
|
||||||
|
const remoteJid = data.remoteJid;
|
||||||
|
const url = data.url;
|
||||||
|
const typebot = data.typebot;
|
||||||
|
|
||||||
|
const id = Math.floor(Math.random() * 10000000000).toString();
|
||||||
|
|
||||||
|
const reqData = {
|
||||||
|
sessionId: id,
|
||||||
|
startParams: {
|
||||||
|
typebot: data.typebot,
|
||||||
|
prefilledVariables: {
|
||||||
|
remoteJid: data.remoteJid,
|
||||||
|
pushName: data.pushName,
|
||||||
|
instanceName: instance.instanceName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
console.log(reqData);
|
||||||
|
|
||||||
|
const request = await axios.post(data.url + '/api/v1/sendMessage', reqData);
|
||||||
|
|
||||||
|
await this.sendWAMessage(
|
||||||
|
instance,
|
||||||
|
remoteJid,
|
||||||
|
request.data.messages,
|
||||||
|
request.data.input,
|
||||||
|
request.data.clientSideActions,
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
typebot: {
|
||||||
|
...instance,
|
||||||
|
typebot: {
|
||||||
|
url: url,
|
||||||
|
remoteJid: remoteJid,
|
||||||
|
typebot: typebot,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private getTypeMessage(msg: any) {
|
||||||
|
this.logger.verbose('get type message');
|
||||||
|
|
||||||
|
const types = {
|
||||||
|
conversation: msg.conversation,
|
||||||
|
extendedTextMessage: msg.extendedTextMessage?.text,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.logger.verbose('type message: ' + types);
|
||||||
|
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getMessageContent(types: any) {
|
||||||
|
this.logger.verbose('get message content');
|
||||||
|
const typeKey = Object.keys(types).find((key) => types[key] !== undefined);
|
||||||
|
|
||||||
|
const result = typeKey ? types[typeKey] : undefined;
|
||||||
|
|
||||||
|
this.logger.verbose('message content: ' + result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getConversationMessage(msg: any) {
|
||||||
|
this.logger.verbose('get conversation message');
|
||||||
|
|
||||||
|
const types = this.getTypeMessage(msg);
|
||||||
|
|
||||||
|
const messageContent = this.getMessageContent(types);
|
||||||
|
|
||||||
|
this.logger.verbose('conversation message: ' + messageContent);
|
||||||
|
|
||||||
|
return messageContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async createNewSession(instance: InstanceDto, data: any) {
|
||||||
|
const id = Math.floor(Math.random() * 10000000000).toString();
|
||||||
|
const reqData = {
|
||||||
|
sessionId: id,
|
||||||
|
startParams: {
|
||||||
|
typebot: data.typebot,
|
||||||
|
prefilledVariables: {
|
||||||
|
remoteJid: data.remoteJid,
|
||||||
|
pushName: data.pushName,
|
||||||
|
instanceName: instance.instanceName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const request = await axios.post(data.url + '/api/v1/sendMessage', reqData);
|
||||||
|
|
||||||
|
if (request.data.sessionId) {
|
||||||
|
data.sessions.push({
|
||||||
|
remoteJid: data.remoteJid,
|
||||||
|
sessionId: `${id}-${request.data.sessionId}`,
|
||||||
|
status: 'opened',
|
||||||
|
createdAt: Date.now(),
|
||||||
|
updateAt: Date.now(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const typebotData = {
|
||||||
|
enabled: true,
|
||||||
|
url: data.url,
|
||||||
|
typebot: data.typebot,
|
||||||
|
expire: data.expire,
|
||||||
|
keyword_finish: data.keyword_finish,
|
||||||
|
delay_message: data.delay_message,
|
||||||
|
unknown_message: data.unknown_message,
|
||||||
|
sessions: data.sessions,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.create(instance, typebotData);
|
||||||
|
}
|
||||||
|
|
||||||
|
return request.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async sendWAMessage(
|
||||||
|
instance: InstanceDto,
|
||||||
|
remoteJid: string,
|
||||||
|
messages: any[],
|
||||||
|
input: any[],
|
||||||
|
clientSideActions: any[],
|
||||||
|
) {
|
||||||
|
processMessages(this.waMonitor.waInstances[instance.instanceName], messages, input, clientSideActions).catch(
|
||||||
|
(err) => {
|
||||||
|
console.error('Erro ao processar mensagens:', err);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
function findItemAndGetSecondsToWait(array, targetId) {
|
||||||
|
if (!array) return null;
|
||||||
|
|
||||||
|
for (const item of array) {
|
||||||
|
if (item.lastBubbleBlockId === targetId) {
|
||||||
|
return item.wait?.secondsToWaitFor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function processMessages(instance, messages, input, clientSideActions) {
|
||||||
|
for (const message of messages) {
|
||||||
|
const wait = findItemAndGetSecondsToWait(clientSideActions, message.id);
|
||||||
|
|
||||||
|
if (message.type === 'text') {
|
||||||
|
let formattedText = '';
|
||||||
|
|
||||||
|
let linkPreview = false;
|
||||||
|
|
||||||
|
for (const richText of message.content.richText) {
|
||||||
|
for (const element of richText.children) {
|
||||||
|
let text = '';
|
||||||
|
if (element.text) {
|
||||||
|
text = element.text;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element.bold) {
|
||||||
|
text = `*${text}*`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element.italic) {
|
||||||
|
text = `_${text}_`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element.underline) {
|
||||||
|
text = `~${text}~`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element.url) {
|
||||||
|
const linkText = element.children[0].text;
|
||||||
|
text = `[${linkText}](${element.url})`;
|
||||||
|
linkPreview = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
formattedText += text;
|
||||||
|
}
|
||||||
|
formattedText += '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
formattedText = formattedText.replace(/\n$/, '');
|
||||||
|
|
||||||
|
await instance.textMessage({
|
||||||
|
number: remoteJid.split('@')[0],
|
||||||
|
options: {
|
||||||
|
delay: wait ? wait * 1000 : instance.localTypebot.delay_message || 1000,
|
||||||
|
presence: 'composing',
|
||||||
|
linkPreview: linkPreview,
|
||||||
|
},
|
||||||
|
textMessage: {
|
||||||
|
text: formattedText,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.type === 'image') {
|
||||||
|
await instance.mediaMessage({
|
||||||
|
number: remoteJid.split('@')[0],
|
||||||
|
options: {
|
||||||
|
delay: wait ? wait * 1000 : instance.localTypebot.delay_message || 1000,
|
||||||
|
presence: 'composing',
|
||||||
|
},
|
||||||
|
mediaMessage: {
|
||||||
|
mediatype: 'image',
|
||||||
|
media: message.content.url,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.type === 'video') {
|
||||||
|
await instance.mediaMessage({
|
||||||
|
number: remoteJid.split('@')[0],
|
||||||
|
options: {
|
||||||
|
delay: wait ? wait * 1000 : instance.localTypebot.delay_message || 1000,
|
||||||
|
presence: 'composing',
|
||||||
|
},
|
||||||
|
mediaMessage: {
|
||||||
|
mediatype: 'video',
|
||||||
|
media: message.content.url,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.type === 'audio') {
|
||||||
|
await instance.audioWhatsapp({
|
||||||
|
number: remoteJid.split('@')[0],
|
||||||
|
options: {
|
||||||
|
delay: wait ? wait * 1000 : instance.localTypebot.delay_message || 1000,
|
||||||
|
presence: 'recording',
|
||||||
|
encoding: true,
|
||||||
|
},
|
||||||
|
audioMessage: {
|
||||||
|
audio: message.content.url,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input) {
|
||||||
|
if (input.type === 'choice input') {
|
||||||
|
let formattedText = '';
|
||||||
|
|
||||||
|
const items = input.items;
|
||||||
|
|
||||||
|
for (const item of items) {
|
||||||
|
formattedText += `▶️ ${item.content}\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
formattedText = formattedText.replace(/\n$/, '');
|
||||||
|
|
||||||
|
await instance.textMessage({
|
||||||
|
number: remoteJid.split('@')[0],
|
||||||
|
options: {
|
||||||
|
delay: 1200,
|
||||||
|
presence: 'composing',
|
||||||
|
linkPreview: false,
|
||||||
|
},
|
||||||
|
textMessage: {
|
||||||
|
text: formattedText,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async sendTypebot(instance: InstanceDto, remoteJid: string, msg: MessageRaw) {
|
||||||
|
const url = (await this.find(instance)).url;
|
||||||
|
const typebot = (await this.find(instance)).typebot;
|
||||||
|
const sessions = ((await this.find(instance)).sessions as Session[]) ?? [];
|
||||||
|
const expire = (await this.find(instance)).expire;
|
||||||
|
const keyword_finish = (await this.find(instance)).keyword_finish;
|
||||||
|
const delay_message = (await this.find(instance)).delay_message;
|
||||||
|
const unknown_message = (await this.find(instance)).unknown_message;
|
||||||
|
|
||||||
|
const session = sessions.find((session) => session.remoteJid === remoteJid);
|
||||||
|
|
||||||
|
if (session && expire && expire > 0) {
|
||||||
|
const now = Date.now();
|
||||||
|
|
||||||
|
const diff = now - session.updateAt;
|
||||||
|
|
||||||
|
const diffInMinutes = Math.floor(diff / 1000 / 60);
|
||||||
|
|
||||||
|
if (diffInMinutes > expire) {
|
||||||
|
sessions.splice(sessions.indexOf(session), 1);
|
||||||
|
|
||||||
|
const data = await this.createNewSession(instance, {
|
||||||
|
url: url,
|
||||||
|
typebot: typebot,
|
||||||
|
expire: expire,
|
||||||
|
keyword_finish: keyword_finish,
|
||||||
|
delay_message: delay_message,
|
||||||
|
unknown_message: unknown_message,
|
||||||
|
sessions: sessions,
|
||||||
|
remoteJid: remoteJid,
|
||||||
|
pushName: msg.pushName,
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.sendWAMessage(instance, remoteJid, data.messages, data.input, data.clientSideActions);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session && session.status !== 'opened') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!session) {
|
||||||
|
const data = await this.createNewSession(instance, {
|
||||||
|
url: url,
|
||||||
|
typebot: typebot,
|
||||||
|
expire: expire,
|
||||||
|
keyword_finish: keyword_finish,
|
||||||
|
delay_message: delay_message,
|
||||||
|
unknown_message: unknown_message,
|
||||||
|
sessions: sessions,
|
||||||
|
remoteJid: remoteJid,
|
||||||
|
pushName: msg.pushName,
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.sendWAMessage(instance, remoteJid, data.messages, data.input, data.clientSideActions);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sessions.map((session) => {
|
||||||
|
if (session.remoteJid === remoteJid) {
|
||||||
|
session.updateAt = Date.now();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const typebotData = {
|
||||||
|
enabled: true,
|
||||||
|
url: url,
|
||||||
|
typebot: typebot,
|
||||||
|
expire: expire,
|
||||||
|
keyword_finish: keyword_finish,
|
||||||
|
delay_message: delay_message,
|
||||||
|
unknown_message: unknown_message,
|
||||||
|
sessions,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.create(instance, typebotData);
|
||||||
|
|
||||||
|
const content = this.getConversationMessage(msg.message);
|
||||||
|
|
||||||
|
if (!content) {
|
||||||
|
if (unknown_message) {
|
||||||
|
this.waMonitor.waInstances[instance.instanceName].textMessage({
|
||||||
|
number: remoteJid.split('@')[0],
|
||||||
|
options: {
|
||||||
|
delay: delay_message || 1000,
|
||||||
|
presence: 'composing',
|
||||||
|
},
|
||||||
|
textMessage: {
|
||||||
|
text: unknown_message,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (content.toLowerCase() === keyword_finish.toLowerCase()) {
|
||||||
|
sessions.splice(sessions.indexOf(session), 1);
|
||||||
|
|
||||||
|
const typebotData = {
|
||||||
|
enabled: true,
|
||||||
|
url: url,
|
||||||
|
typebot: typebot,
|
||||||
|
expire: expire,
|
||||||
|
keyword_finish: keyword_finish,
|
||||||
|
delay_message: delay_message,
|
||||||
|
unknown_message: unknown_message,
|
||||||
|
sessions,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.create(instance, typebotData);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const reqData = {
|
||||||
|
message: content,
|
||||||
|
sessionId: session.sessionId.split('-')[1],
|
||||||
|
};
|
||||||
|
|
||||||
|
const request = await axios.post(url + '/api/v1/sendMessage', reqData);
|
||||||
|
|
||||||
|
await this.sendWAMessage(
|
||||||
|
instance,
|
||||||
|
remoteJid,
|
||||||
|
request.data.messages,
|
||||||
|
request.data.input,
|
||||||
|
request.data.clientSideActions,
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
|
import { Logger } from '../../config/logger.config';
|
||||||
import { InstanceDto } from '../dto/instance.dto';
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
import { WebhookDto } from '../dto/webhook.dto';
|
import { WebhookDto } from '../dto/webhook.dto';
|
||||||
import { WAMonitoringService } from './monitor.service';
|
import { WAMonitoringService } from './monitor.service';
|
||||||
import { Logger } from '../../config/logger.config';
|
|
||||||
|
|
||||||
export class WebhookService {
|
export class WebhookService {
|
||||||
constructor(private readonly waMonitor: WAMonitoringService) {}
|
constructor(private readonly waMonitor: WAMonitoringService) {}
|
||||||
@@ -18,9 +18,7 @@ export class WebhookService {
|
|||||||
public async find(instance: InstanceDto): Promise<WebhookDto> {
|
public async find(instance: InstanceDto): Promise<WebhookDto> {
|
||||||
try {
|
try {
|
||||||
this.logger.verbose('find webhook: ' + instance.instanceName);
|
this.logger.verbose('find webhook: ' + instance.instanceName);
|
||||||
const result = await this.waMonitor.waInstances[
|
const result = await this.waMonitor.waInstances[instance.instanceName].findWebhook();
|
||||||
instance.instanceName
|
|
||||||
].findWebhook();
|
|
||||||
|
|
||||||
if (Object.keys(result).length === 0) {
|
if (Object.keys(result).length === 0) {
|
||||||
throw new Error('Webhook not found');
|
throw new Error('Webhook not found');
|
||||||
|
|||||||
33
src/whatsapp/services/websocket.service.ts
Normal file
33
src/whatsapp/services/websocket.service.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { Logger } from '../../config/logger.config';
|
||||||
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
|
import { WebsocketDto } from '../dto/websocket.dto';
|
||||||
|
import { WebsocketRaw } from '../models';
|
||||||
|
import { WAMonitoringService } from './monitor.service';
|
||||||
|
|
||||||
|
export class WebsocketService {
|
||||||
|
constructor(private readonly waMonitor: WAMonitoringService) {}
|
||||||
|
|
||||||
|
private readonly logger = new Logger(WebsocketService.name);
|
||||||
|
|
||||||
|
public create(instance: InstanceDto, data: WebsocketDto) {
|
||||||
|
this.logger.verbose('create websocket: ' + instance.instanceName);
|
||||||
|
this.waMonitor.waInstances[instance.instanceName].setWebsocket(data);
|
||||||
|
|
||||||
|
return { websocket: { ...instance, websocket: data } };
|
||||||
|
}
|
||||||
|
|
||||||
|
public async find(instance: InstanceDto): Promise<WebsocketRaw> {
|
||||||
|
try {
|
||||||
|
this.logger.verbose('find websocket: ' + instance.instanceName);
|
||||||
|
const result = await this.waMonitor.waInstances[instance.instanceName].findWebsocket();
|
||||||
|
|
||||||
|
if (Object.keys(result).length === 0) {
|
||||||
|
throw new Error('Websocket not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
return { enabled: false, events: [] };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user