Skip to content

Commit ceee6a7

Browse files
committed
Merge branch 'release/1.7.6'
2 parents da06ed1 + ebfc6d4 commit ceee6a7

File tree

19 files changed

+445
-107
lines changed

19 files changed

+445
-107
lines changed

.github/workflows/publish_docker_image.yml

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,52 +2,49 @@ name: Build Docker image
22

33
on:
44
push:
5-
branches:
6-
- develop
7-
- main
85
tags:
9-
- v*
10-
workflow_dispatch:
6+
- "v*.*.*"
117

128
jobs:
13-
build:
9+
build_deploy:
10+
name: Build and Deploy
1411
runs-on: ubuntu-latest
15-
env:
16-
GIT_REF: ${{ github.head_ref || github.ref_name }} # ref_name to get tags/branches
1712
permissions:
1813
contents: read
1914
packages: write
2015
steps:
2116
- name: Checkout
2217
uses: actions/checkout@v4
2318

19+
- name: Docker meta
20+
id: meta
21+
uses: docker/metadata-action@v5
22+
with:
23+
images: atendai/evolution-api
24+
tags: |
25+
type=semver,pattern={{version}}
26+
type=semver,pattern={{major}}.{{minor}}
27+
2428
- name: Set up QEMU
2529
uses: docker/setup-qemu-action@v3
2630

2731
- name: Set up Docker Buildx
2832
uses: docker/setup-buildx-action@v3
2933

30-
- name: set docker tag
31-
run: |
32-
echo "DOCKER_TAG=ghcr.io/atendai/evolution-api:$GIT_REF" >> $GITHUB_ENV
33-
34-
- name: replace docker tag if main
35-
if: github.ref_name == 'main'
36-
run: |
37-
echo "DOCKER_TAG=ghcr.io/atendai/evolution-api:latest" >> $GITHUB_ENV
38-
3934
- name: Login to GitHub Container Registry
4035
uses: docker/login-action@v3
4136
with:
42-
registry: ghcr.io
43-
username: ${{ github.actor }}
44-
password: ${{ secrets.GITHUB_TOKEN }}
37+
username: ${{ secrets.DOCKER_USERNAME }}
38+
password: ${{ secrets.DOCKER_PASSWORD }}
4539

4640
- name: Build and push
47-
uses: docker/build-push-action@v2
41+
id: docker_build
42+
uses: docker/build-push-action@v5
4843
with:
49-
context: .
50-
file: ./Dockerfile
5144
platforms: linux/amd64,linux/arm64
5245
push: true
53-
tags: ${{ env.DOCKER_TAG }}
46+
tags: ${{ steps.meta.outputs.tags }}
47+
labels: ${{ steps.meta.outputs.labels }}
48+
49+
- name: Image digest
50+
run: echo ${{ steps.docker_build.outputs.digest }}

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
# 1.8.0 (develop)
2+
3+
### Feature
4+
5+
* Now in the manager, when logging in with the client's apikey, the listing only shows the instance corresponding to the provided apikey (only with MongoDB)
6+
* New global mode for rabbitmq events
7+
8+
### Fixed
9+
* Correction in message formatting when generated by AI as markdown in typebot
10+
111
# 1.7.5 (2024-05-21 08:50)
212

313
### Fixed

Docker/.env.example

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,33 @@ DATABASE_SAVE_DATA_CONTACTS=false
4747
DATABASE_SAVE_DATA_CHATS=false
4848

4949
RABBITMQ_ENABLED=false
50-
RABBITMQ_RABBITMQ_MODE=global
51-
RABBITMQ_EXCHANGE_NAME=evolution_exchange
5250
RABBITMQ_URI=amqp://guest:guest@rabbitmq:5672
51+
RABBITMQ_EXCHANGE_NAME=evolution_exchange
52+
RABBITMQ_GLOBAL_ENABLED=false
53+
RABBITMQ_EVENTS_APPLICATION_STARTUP=false
54+
RABBITMQ_EVENTS_QRCODE_UPDATED=true
55+
RABBITMQ_EVENTS_MESSAGES_SET=true
56+
RABBITMQ_EVENTS_MESSAGES_UPSERT=true
57+
RABBITMQ_EVENTS_MESSAGES_UPDATE=true
58+
RABBITMQ_EVENTS_MESSAGES_DELETE=true
59+
RABBITMQ_EVENTS_SEND_MESSAGE=true
60+
RABBITMQ_EVENTS_CONTACTS_SET=true
61+
RABBITMQ_EVENTS_CONTACTS_UPSERT=true
62+
RABBITMQ_EVENTS_CONTACTS_UPDATE=true
63+
RABBITMQ_EVENTS_PRESENCE_UPDATE=true
64+
RABBITMQ_EVENTS_CHATS_SET=true
65+
RABBITMQ_EVENTS_CHATS_UPSERT=true
66+
RABBITMQ_EVENTS_CHATS_UPDATE=true
67+
RABBITMQ_EVENTS_CHATS_DELETE=true
68+
RABBITMQ_EVENTS_GROUPS_UPSERT=true
69+
RABBITMQ_EVENTS_GROUPS_UPDATE=true
70+
RABBITMQ_EVENTS_GROUP_PARTICIPANTS_UPDATE=true
71+
RABBITMQ_EVENTS_CONNECTION_UPDATE=true
72+
RABBITMQ_EVENTS_LABELS_EDIT=true
73+
RABBITMQ_EVENTS_LABELS_ASSOCIATION=true
74+
RABBITMQ_EVENTS_CALL=true
75+
RABBITMQ_EVENTS_TYPEBOT_START=false
76+
RABBITMQ_EVENTS_TYPEBOT_CHANGE_STATUS=false
5377

5478
WEBSOCKET_ENABLED=false
5579
WEBSOCKET_GLOBAL_EVENTS=false
@@ -125,7 +149,7 @@ CHATWOOT_MESSAGE_DELETE=false # false | true
125149
# If you leave this option as true, when sending a message in Chatwoot, the client's last message will be marked as read on WhatsApp.
126150
CHATWOOT_MESSAGE_READ=false # false | true
127151
# This db connection is used to import messages from whatsapp to chatwoot database
128-
CHATWOOT_IMPORT_DATABASE_CONNECTION_URI=postgres://user:password@hostname:port/dbname
152+
CHATWOOT_IMPORT_DATABASE_CONNECTION_URI=postgres://user:password@hostname:port/dbname?sslmode=disable
129153
CHATWOOT_IMPORT_DATABASE_PLACEHOLDER_MEDIA_MESSAGE=true
130154

131155
CACHE_REDIS_ENABLED=false

Dockerfile

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
FROM node:20.7.0-alpine AS builder
22

3-
LABEL version="1.7.5" description="Api to control whatsapp features through http requests."
3+
LABEL version="1.8.0" description="Api to control whatsapp features through http requests."
44
LABEL maintainer="Davidson Gomes" git="https://github.com/DavidsonGomes"
55
LABEL contact="contato@agenciadgcode.com"
66

@@ -59,9 +59,35 @@ ENV DATABASE_SAVE_DATA_CONTACTS=false
5959
ENV DATABASE_SAVE_DATA_CHATS=false
6060

6161
ENV RABBITMQ_ENABLED=false
62-
ENV RABBITMQ_MODE=global
63-
ENV RABBITMQ_EXCHANGE_NAME=evolution_exchange
6462
ENV RABBITMQ_URI=amqp://guest:guest@rabbitmq:5672
63+
ENV RABBITMQ_EXCHANGE_NAME=evolution_exchange
64+
ENV RABBITMQ_GLOBAL_ENABLED=false
65+
ENV RABBITMQ_EVENTS_APPLICATION_STARTUP=false
66+
ENV RABBITMQ_EVENTS_INSTANCE_CREATE=false
67+
ENV RABBITMQ_EVENTS_INSTANCE_DELETE=false
68+
ENV RABBITMQ_EVENTS_QRCODE_UPDATED=true
69+
ENV RABBITMQ_EVENTS_MESSAGES_SET=true
70+
ENV RABBITMQ_EVENTS_MESSAGES_UPSERT=true
71+
ENV RABBITMQ_EVENTS_MESSAGES_UPDATE=true
72+
ENV RABBITMQ_EVENTS_MESSAGES_DELETE=true
73+
ENV RABBITMQ_EVENTS_SEND_MESSAGE=true
74+
ENV RABBITMQ_EVENTS_CONTACTS_SET=true
75+
ENV RABBITMQ_EVENTS_CONTACTS_UPSERT=true
76+
ENV RABBITMQ_EVENTS_CONTACTS_UPDATE=true
77+
ENV RABBITMQ_EVENTS_PRESENCE_UPDATE=true
78+
ENV RABBITMQ_EVENTS_CHATS_SET=true
79+
ENV RABBITMQ_EVENTS_CHATS_UPSERT=true
80+
ENV RABBITMQ_EVENTS_CHATS_UPDATE=true
81+
ENV RABBITMQ_EVENTS_CHATS_DELETE=true
82+
ENV RABBITMQ_EVENTS_GROUPS_UPSERT=true
83+
ENV RABBITMQ_EVENTS_GROUPS_UPDATE=true
84+
ENV RABBITMQ_EVENTS_GROUP_PARTICIPANTS_UPDATE=true
85+
ENV RABBITMQ_EVENTS_CONNECTION_UPDATE=true
86+
ENV RABBITMQ_EVENTS_LABELS_EDIT=true
87+
ENV RABBITMQ_EVENTS_LABELS_ASSOCIATION=true
88+
ENV RABBITMQ_EVENTS_CALL=true
89+
ENV RABBITMQ_EVENTS_TYPEBOT_START=false
90+
ENV RABBITMQ_EVENTS_TYPEBOT_CHANGE_STATUS=false
6591

6692
ENV WEBSOCKET_ENABLED=false
6793
ENV WEBSOCKET_GLOBAL_EVENTS=false

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "evolution-api",
3-
"version": "1.7.5",
3+
"version": "1.8.0",
44
"description": "Rest api for communication with WhatsApp",
55
"main": "./dist/src/main.js",
66
"scripts": {

src/api/controllers/instance.controller.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import { isURL } from 'class-validator';
33
import EventEmitter2 from 'eventemitter2';
44
import { v4 } from 'uuid';
55

6-
import { ConfigService, HttpServer, WaBusiness } from '../../config/env.config';
6+
import { Auth, ConfigService, HttpServer, WaBusiness } from '../../config/env.config';
77
import { Logger } from '../../config/logger.config';
8-
import { BadRequestException, InternalServerErrorException } from '../../exceptions';
8+
import { BadRequestException, InternalServerErrorException, UnauthorizedException } from '../../exceptions';
99
import { InstanceDto, SetPresenceDto } from '../dto/instance.dto';
1010
import { ChatwootService } from '../integrations/chatwoot/services/chatwoot.service';
1111
import { RabbitmqService } from '../integrations/rabbitmq/services/rabbitmq.service';
@@ -679,11 +679,26 @@ export class InstanceController {
679679
};
680680
}
681681

682-
public async fetchInstances({ instanceName, instanceId, number }: InstanceDto) {
683-
if (instanceName) {
684-
this.logger.verbose('requested fetchInstances from ' + instanceName + ' instance');
685-
this.logger.verbose('instanceName: ' + instanceName);
686-
return this.waMonitor.instanceInfo(instanceName);
682+
public async fetchInstances({ instanceName, instanceId, number }: InstanceDto, key: string) {
683+
const env = this.configService.get<Auth>('AUTHENTICATION').API_KEY;
684+
685+
let name = instanceName;
686+
let arrayReturn = false;
687+
688+
if (env.KEY !== key) {
689+
const instanceByKey = await this.repository.auth.findByKey(key);
690+
if (instanceByKey) {
691+
name = instanceByKey._id;
692+
arrayReturn = true;
693+
} else {
694+
throw new UnauthorizedException();
695+
}
696+
}
697+
698+
if (name) {
699+
this.logger.verbose('requested fetchInstances from ' + name + ' instance');
700+
this.logger.verbose('instanceName: ' + name);
701+
return this.waMonitor.instanceInfo(name, arrayReturn);
687702
} else if (instanceId || number) {
688703
return this.waMonitor.instanceInfoById(instanceId, number);
689704
}

src/api/guards/auth.guard.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,19 +59,32 @@ async function apikey(req: Request, _: Response, next: NextFunction) {
5959
const env = configService.get<Auth>('AUTHENTICATION').API_KEY;
6060
const key = req.get('apikey');
6161

62+
if (!key) {
63+
throw new UnauthorizedException();
64+
}
65+
6266
if (env.KEY === key) {
6367
return next();
6468
}
6569

6670
if ((req.originalUrl.includes('/instance/create') || req.originalUrl.includes('/instance/fetchInstances')) && !key) {
6771
throw new ForbiddenException('Missing global api key', 'The global api key must be set');
6872
}
73+
const param = req.params as unknown as InstanceDto;
6974

7075
try {
71-
const param = req.params as unknown as InstanceDto;
72-
const instanceKey = await repository.auth.find(param.instanceName);
73-
if (instanceKey.apikey === key) {
74-
return next();
76+
if (param?.instanceName) {
77+
const instanceKey = await repository.auth.find(param.instanceName);
78+
if (instanceKey?.apikey === key) {
79+
return next();
80+
}
81+
} else {
82+
if (req.originalUrl.includes('/instance/fetchInstances')) {
83+
const instanceByKey = await repository.auth.findByKey(key);
84+
if (instanceByKey) {
85+
return next();
86+
}
87+
}
7588
}
7689
} catch (error) {
7790
logger.error(error);

src/api/integrations/rabbitmq/libs/amqp.server.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,41 @@ export const getAMQP = (): amqp.Channel | null => {
4242
return amqpChannel;
4343
};
4444

45+
export const initGlobalQueues = () => {
46+
logger.info('Initializing global queues');
47+
const events = configService.get<Rabbitmq>('RABBITMQ').EVENTS;
48+
49+
if (!events) {
50+
logger.warn('No events to initialize on AMQP');
51+
return;
52+
}
53+
54+
const eventKeys = Object.keys(events);
55+
56+
eventKeys.forEach((event) => {
57+
if (events[event] === false) return;
58+
59+
const queueName = `${event.replace(/_/g, '.').toLowerCase()}`;
60+
const amqp = getAMQP();
61+
const exchangeName = 'evolution_exchange';
62+
63+
amqp.assertExchange(exchangeName, 'topic', {
64+
durable: true,
65+
autoDelete: false,
66+
});
67+
68+
amqp.assertQueue(queueName, {
69+
durable: true,
70+
autoDelete: false,
71+
arguments: {
72+
'x-queue-type': 'quorum',
73+
},
74+
});
75+
76+
amqp.bindQueue(queueName, exchangeName, event);
77+
});
78+
};
79+
4580
export const initQueues = (instanceName: string, events: string[]) => {
4681
if (!events || !events.length) return;
4782

src/api/integrations/typebot/services/typebot.service.ts

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -519,18 +519,32 @@ export class TypebotService {
519519
text += element.text;
520520
}
521521

522-
if (
523-
element.children &&
524-
(element.type === 'p' ||
525-
element.type === 'a' ||
526-
element.type === 'inline-variable' ||
527-
element.type === 'variable')
528-
) {
522+
if (element.children && element.type !== 'a') {
529523
for (const child of element.children) {
530524
text += applyFormatting(child);
531525
}
532526
}
533527

528+
if (element.type === 'p') {
529+
text = text.trim() + '\n';
530+
}
531+
532+
if (element.type === 'ol') {
533+
text =
534+
'\n' +
535+
text
536+
.split('\n')
537+
.map((line, index) => (line ? `${index + 1}. ${line}` : ''))
538+
.join('\n');
539+
}
540+
541+
if (element.type === 'li') {
542+
text = text
543+
.split('\n')
544+
.map((line) => (line ? ` ${line}` : ''))
545+
.join('\n');
546+
}
547+
534548
let formats = '';
535549

536550
if (element.bold) {

src/api/repository/auth.repository.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,20 @@ export class AuthRepository extends Repository {
6868
}
6969
}
7070

71+
public async findByKey(key: string): Promise<AuthRaw> {
72+
try {
73+
this.logger.verbose('finding auth');
74+
if (this.dbSettings.ENABLED) {
75+
this.logger.verbose('finding auth in db');
76+
return await this.authModel.findOne({ apikey: key });
77+
}
78+
79+
return {};
80+
} catch (error) {
81+
return {};
82+
}
83+
}
84+
7185
public async list(): Promise<AuthRaw[]> {
7286
try {
7387
if (this.dbSettings.ENABLED) {

0 commit comments

Comments
 (0)