mirror of
https://github.com/EvolutionAPI/evolution-api.git
synced 2025-12-19 11:52:20 -06:00
Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8fe75cd210 | ||
|
|
303effebbc | ||
|
|
f32a34190d | ||
|
|
8588ef1d8a | ||
|
|
51ec4821f3 | ||
|
|
957033a7bb | ||
|
|
62c74deac3 | ||
|
|
29fd448998 | ||
|
|
e55cb08a6a | ||
|
|
047359e8dc | ||
|
|
eb814e181a | ||
|
|
857031ff5a | ||
|
|
d5eeb68714 | ||
|
|
966b287026 | ||
|
|
a348729109 | ||
|
|
1f29b7733e | ||
|
|
e26ae30f6f | ||
|
|
547943a05c | ||
|
|
46aa229531 | ||
|
|
28bd796289 | ||
|
|
6a3f82ed7e | ||
|
|
523f3301c0 | ||
|
|
f085343a99 | ||
|
|
f76a924700 | ||
|
|
f8e3b76a4a | ||
|
|
b8f1e8a7ef | ||
|
|
d007fc49d8 | ||
|
|
f6d8ebd8d3 | ||
|
|
6ff9c4578a | ||
|
|
33acfe1464 | ||
|
|
f5eeb16bb1 | ||
|
|
c35c5faaa4 | ||
|
|
8425ebc13f | ||
|
|
6fc37a4298 | ||
|
|
99f3e77c12 | ||
|
|
a9c087c45f | ||
|
|
3f4333087f | ||
|
|
e1ac29683d | ||
|
|
5c74cbfe19 | ||
|
|
3fdb3fa673 | ||
|
|
ba584974cb |
24
CHANGELOG.md
24
CHANGELOG.md
@@ -1,3 +1,27 @@
|
|||||||
|
# 1.5.4 (2023-10-09 20:43)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* Baileys logger typing issue resolved
|
||||||
|
* Solved problem with duplicate messages in chatwoot
|
||||||
|
|
||||||
|
# 1.5.3 (2023-10-06 18:55)
|
||||||
|
|
||||||
|
### Feature
|
||||||
|
|
||||||
|
* Swagger documentation
|
||||||
|
* Added base 64 sending option via webhook
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* Remove rabbitmq queues when delete instances
|
||||||
|
* Improvement in restart instance to completely redo the connection
|
||||||
|
* Update node version: v20
|
||||||
|
* Correction of messages sent by the api and typebot not appearing in chatwoot
|
||||||
|
* Adjustment to start typebot, added startSession parameter
|
||||||
|
* Chatwoot now receives messages sent via api and typebot
|
||||||
|
* Fixed problem with starting with an input in typebot
|
||||||
|
* Added check to ensure variables are not empty before executing foreach in start typebot
|
||||||
|
|
||||||
# 1.5.2 (2023-09-28 17:56)
|
# 1.5.2 (2023-09-28 17:56)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
FROM node:16.18-alpine
|
FROM node:20.7.0-alpine
|
||||||
|
|
||||||
LABEL version="1.5.2" description="Api to control whatsapp features through http requests."
|
LABEL version="1.5.4" 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"
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "evolution-api",
|
"name": "evolution-api",
|
||||||
"version": "1.5.2",
|
"version": "1.5.4",
|
||||||
"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": {
|
||||||
@@ -78,7 +78,9 @@
|
|||||||
"sharp": "^0.30.7",
|
"sharp": "^0.30.7",
|
||||||
"socket.io": "^4.7.1",
|
"socket.io": "^4.7.1",
|
||||||
"socks-proxy-agent": "^8.0.1",
|
"socks-proxy-agent": "^8.0.1",
|
||||||
"uuid": "^9.0.0"
|
"swagger-ui-express": "^5.0.0",
|
||||||
|
"uuid": "^9.0.0",
|
||||||
|
"yamljs": "^0.3.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/compression": "^1.7.2",
|
"@types/compression": "^1.7.2",
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
17
src/docs/swagger.conf.ts
Normal file
17
src/docs/swagger.conf.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { Router } from 'express';
|
||||||
|
import { join } from 'path';
|
||||||
|
import swaggerUi from 'swagger-ui-express';
|
||||||
|
import YAML from 'yamljs';
|
||||||
|
|
||||||
|
const document = YAML.load(join(process.cwd(), 'src', 'docs', 'swagger.yaml'));
|
||||||
|
|
||||||
|
const router = Router();
|
||||||
|
|
||||||
|
export const swaggerRouter = router.use('/docs', swaggerUi.serve).get(
|
||||||
|
'/docs',
|
||||||
|
swaggerUi.setup(document, {
|
||||||
|
customCssUrl: '/css/dark-theme-swagger.css',
|
||||||
|
customSiteTitle: 'Evolution API',
|
||||||
|
customfavIcon: '/images/logo.svg',
|
||||||
|
}),
|
||||||
|
);
|
||||||
2597
src/docs/swagger.yaml
Normal file
2597
src/docs/swagger.yaml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -71,3 +71,30 @@ export const initQueues = (instanceName: string, events: string[]) => {
|
|||||||
amqp.bindQueue(queueName, exchangeName, event);
|
amqp.bindQueue(queueName, exchangeName, event);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const removeQueues = (instanceName: string, events: string[]) => {
|
||||||
|
if (!events || !events.length) return;
|
||||||
|
|
||||||
|
const channel = getAMQP();
|
||||||
|
|
||||||
|
const queues = events.map((event) => {
|
||||||
|
return `${event.replace(/_/g, '.').toLowerCase()}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
const exchangeName = instanceName ?? 'evolution_exchange';
|
||||||
|
|
||||||
|
queues.forEach((event) => {
|
||||||
|
const amqp = getAMQP();
|
||||||
|
|
||||||
|
amqp.assertExchange(exchangeName, 'topic', {
|
||||||
|
durable: true,
|
||||||
|
autoDelete: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const queueName = `${instanceName}.${event}`;
|
||||||
|
|
||||||
|
amqp.deleteQueue(queueName);
|
||||||
|
});
|
||||||
|
|
||||||
|
channel.deleteExchange(exchangeName);
|
||||||
|
};
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { Auth, configService, Cors, HttpServer, Rabbitmq, Webhook } from './conf
|
|||||||
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 { swaggerRouter } from './docs/swagger.conf';
|
||||||
import { initAMQP } from './libs/amqp.server';
|
import { initAMQP } from './libs/amqp.server';
|
||||||
import { initIO } from './libs/socket.server';
|
import { initIO } from './libs/socket.server';
|
||||||
import { ServerUP } from './utils/server-up';
|
import { ServerUP } from './utils/server-up';
|
||||||
@@ -51,6 +52,7 @@ function bootstrap() {
|
|||||||
app.use('/store', express.static(join(ROOT_DIR, 'store')));
|
app.use('/store', express.static(join(ROOT_DIR, 'store')));
|
||||||
|
|
||||||
app.use('/', router);
|
app.use('/', router);
|
||||||
|
app.use(swaggerRouter);
|
||||||
|
|
||||||
app.use(
|
app.use(
|
||||||
(err: Error, req: Request, res: Response, next: NextFunction) => {
|
(err: Error, req: Request, res: Response, next: NextFunction) => {
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ export class InstanceController {
|
|||||||
instanceName,
|
instanceName,
|
||||||
webhook,
|
webhook,
|
||||||
webhook_by_events,
|
webhook_by_events,
|
||||||
|
webhook_base64,
|
||||||
events,
|
events,
|
||||||
qrcode,
|
qrcode,
|
||||||
number,
|
number,
|
||||||
@@ -139,6 +140,7 @@ export class InstanceController {
|
|||||||
url: webhook,
|
url: webhook,
|
||||||
events: newEvents,
|
events: newEvents,
|
||||||
webhook_by_events,
|
webhook_by_events,
|
||||||
|
webhook_base64,
|
||||||
});
|
});
|
||||||
|
|
||||||
webhookEvents = (await this.webhookService.find(instance)).events;
|
webhookEvents = (await this.webhookService.find(instance)).events;
|
||||||
@@ -297,6 +299,7 @@ export class InstanceController {
|
|||||||
webhook: {
|
webhook: {
|
||||||
webhook,
|
webhook,
|
||||||
webhook_by_events,
|
webhook_by_events,
|
||||||
|
webhook_base64,
|
||||||
events: webhookEvents,
|
events: webhookEvents,
|
||||||
},
|
},
|
||||||
websocket: {
|
websocket: {
|
||||||
@@ -390,6 +393,7 @@ export class InstanceController {
|
|||||||
webhook: {
|
webhook: {
|
||||||
webhook,
|
webhook,
|
||||||
webhook_by_events,
|
webhook_by_events,
|
||||||
|
webhook_base64,
|
||||||
events: webhookEvents,
|
events: webhookEvents,
|
||||||
},
|
},
|
||||||
websocket: {
|
websocket: {
|
||||||
@@ -475,10 +479,19 @@ export class InstanceController {
|
|||||||
try {
|
try {
|
||||||
this.logger.verbose('requested restartInstance from ' + instanceName + ' instance');
|
this.logger.verbose('requested restartInstance from ' + instanceName + ' instance');
|
||||||
|
|
||||||
this.logger.verbose('logging out instance: ' + instanceName);
|
const instance = this.waMonitor.waInstances[instanceName];
|
||||||
this.waMonitor.waInstances[instanceName]?.client?.ws?.close();
|
const state = instance?.connectionStatus?.state;
|
||||||
|
|
||||||
return { status: 'SUCCESS', error: false, response: { message: 'Instance restarted' } };
|
switch (state) {
|
||||||
|
case 'open':
|
||||||
|
this.logger.verbose('logging out instance: ' + instanceName);
|
||||||
|
await instance.reloadConnection();
|
||||||
|
await delay(2000);
|
||||||
|
|
||||||
|
return await this.connectionState({ instanceName });
|
||||||
|
default:
|
||||||
|
return await this.connectionState({ instanceName });
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.error(error);
|
this.logger.error(error);
|
||||||
}
|
}
|
||||||
@@ -534,6 +547,8 @@ export class InstanceController {
|
|||||||
throw new BadRequestException('The "' + instanceName + '" instance needs to be disconnected');
|
throw new BadRequestException('The "' + instanceName + '" instance needs to be disconnected');
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
this.waMonitor.waInstances[instanceName]?.removeRabbitmqQueues();
|
||||||
|
|
||||||
if (instance.state === 'connecting') {
|
if (instance.state === 'connecting') {
|
||||||
this.logger.verbose('logging out instance: ' + instanceName);
|
this.logger.verbose('logging out instance: ' + instanceName);
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,21 @@
|
|||||||
import { Request, Response } from 'express';
|
import { Request, Response } from 'express';
|
||||||
|
|
||||||
import { ConfigService } from '../../config/env.config';
|
import { Auth, ConfigService, HttpServer } from '../../config/env.config';
|
||||||
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(private readonly waMonit: WAMonitoringService, private readonly configService: ConfigService) {}
|
constructor(private readonly waMonitor: WAMonitoringService, private readonly configService: ConfigService) {}
|
||||||
|
|
||||||
public async manager(request: Request, response: Response) {
|
public async manager(request: Request, response: Response) {
|
||||||
try {
|
try {
|
||||||
return response.status(HttpStatus.OK).render('manager');
|
const token = this.configService.get<Auth>('AUTHENTICATION').API_KEY.KEY;
|
||||||
|
const port = this.configService.get<HttpServer>('SERVER').PORT;
|
||||||
|
|
||||||
|
const instances = await this.waMonitor.instanceInfo();
|
||||||
|
|
||||||
|
console.log('INSTANCES: ', instances);
|
||||||
|
return response.status(HttpStatus.OK).render('manager', { token, port, instances });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('ERROR: ', error);
|
console.log('ERROR: ', error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ export class InstanceDto {
|
|||||||
token?: string;
|
token?: string;
|
||||||
webhook?: string;
|
webhook?: string;
|
||||||
webhook_by_events?: boolean;
|
webhook_by_events?: boolean;
|
||||||
|
webhook_base64?: boolean;
|
||||||
events?: string[];
|
events?: string[];
|
||||||
reject_call?: boolean;
|
reject_call?: boolean;
|
||||||
msg_call?: string;
|
msg_call?: string;
|
||||||
|
|||||||
@@ -3,4 +3,5 @@ export class WebhookDto {
|
|||||||
url?: string;
|
url?: string;
|
||||||
events?: string[];
|
events?: string[];
|
||||||
webhook_by_events?: boolean;
|
webhook_by_events?: boolean;
|
||||||
|
webhook_base64?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ export async function instanceLoggedGuard(req: Request, _: Response, next: NextF
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (waMonitor.waInstances[instance.instanceName]) {
|
if (waMonitor.waInstances[instance.instanceName]) {
|
||||||
|
waMonitor.waInstances[instance.instanceName]?.removeRabbitmqQueues();
|
||||||
delete waMonitor.waInstances[instance.instanceName];
|
delete waMonitor.waInstances[instance.instanceName];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ const typebotSchema = new Schema<TypebotRaw>({
|
|||||||
prefilledVariables: {
|
prefilledVariables: {
|
||||||
remoteJid: { type: String, required: false },
|
remoteJid: { type: String, required: false },
|
||||||
pushName: { type: String, required: false },
|
pushName: { type: String, required: false },
|
||||||
additionalData: { type: Schema.Types.Mixed, required: false }
|
additionalData: { type: Schema.Types.Mixed, required: false },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ export class WebhookRaw {
|
|||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
events?: string[];
|
events?: string[];
|
||||||
webhook_by_events?: boolean;
|
webhook_by_events?: boolean;
|
||||||
|
webhook_base64?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const webhookSchema = new Schema<WebhookRaw>({
|
const webhookSchema = new Schema<WebhookRaw>({
|
||||||
@@ -16,6 +17,7 @@ const webhookSchema = new Schema<WebhookRaw>({
|
|||||||
enabled: { type: Boolean, required: true },
|
enabled: { type: Boolean, required: true },
|
||||||
events: { type: [String], required: true },
|
events: { type: [String], required: true },
|
||||||
webhook_by_events: { type: Boolean, required: true },
|
webhook_by_events: { type: Boolean, required: true },
|
||||||
|
webhook_base64: { type: Boolean, required: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
export const WebhookModel = dbserver?.model(WebhookRaw.name, webhookSchema, 'webhook');
|
export const WebhookModel = dbserver?.model(WebhookRaw.name, webhookSchema, 'webhook');
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ router
|
|||||||
status: HttpStatus.OK,
|
status: HttpStatus.OK,
|
||||||
message: 'Welcome to the Evolution API, it is working!',
|
message: 'Welcome to the Evolution API, it is working!',
|
||||||
version: packageJson.version,
|
version: packageJson.version,
|
||||||
|
documentation: `${req.protocol}://${req.get('host')}/docs`,
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.use('/instance', new InstanceRouter(configService, ...guards).router)
|
.use('/instance', new InstanceRouter(configService, ...guards).router)
|
||||||
|
|||||||
@@ -914,7 +914,7 @@ export class ChatwootService {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
await waInstance?.audioWhatsapp(data);
|
await waInstance?.audioWhatsapp(data, true);
|
||||||
|
|
||||||
this.logger.verbose('audio sent');
|
this.logger.verbose('audio sent');
|
||||||
return;
|
return;
|
||||||
@@ -939,7 +939,7 @@ export class ChatwootService {
|
|||||||
data.mediaMessage.caption = caption;
|
data.mediaMessage.caption = caption;
|
||||||
}
|
}
|
||||||
|
|
||||||
await waInstance?.mediaMessage(data);
|
await waInstance?.mediaMessage(data, true);
|
||||||
|
|
||||||
this.logger.verbose('media sent');
|
this.logger.verbose('media sent');
|
||||||
return;
|
return;
|
||||||
@@ -1074,7 +1074,7 @@ export class ChatwootService {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
await waInstance?.textMessage(data);
|
await waInstance?.textMessage(data, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1132,7 +1132,7 @@ export class ChatwootService {
|
|||||||
thumbnailUrl: string;
|
thumbnailUrl: string;
|
||||||
sourceUrl: string;
|
sourceUrl: string;
|
||||||
}
|
}
|
||||||
const adsMessage: AdsMessage | undefined = msg.extendedTextMessage?.contextInfo.externalAdReply;
|
const adsMessage: AdsMessage | undefined = msg.extendedTextMessage?.contextInfo?.externalAdReply;
|
||||||
|
|
||||||
this.logger.verbose('Get ads message if it exist');
|
this.logger.verbose('Get ads message if it exist');
|
||||||
adsMessage && this.logger.verbose('Ads message: ' + adsMessage);
|
adsMessage && this.logger.verbose('Ads message: ' + adsMessage);
|
||||||
@@ -1279,7 +1279,7 @@ export class ChatwootService {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event === 'messages.upsert') {
|
if (event === 'messages.upsert' || event === 'send.message') {
|
||||||
this.logger.verbose('event messages.upsert');
|
this.logger.verbose('event messages.upsert');
|
||||||
|
|
||||||
if (body.key.remoteJid === 'status@broadcast') {
|
if (body.key.remoteJid === 'status@broadcast') {
|
||||||
|
|||||||
@@ -7,9 +7,7 @@ import { join } from 'path';
|
|||||||
import { Auth, ConfigService, Database, DelInstance, HttpServer, Redis } from '../../config/env.config';
|
import { Auth, ConfigService, Database, DelInstance, HttpServer, Redis } from '../../config/env.config';
|
||||||
import { Logger } from '../../config/logger.config';
|
import { Logger } from '../../config/logger.config';
|
||||||
import { INSTANCE_DIR, STORE_DIR } from '../../config/path.config';
|
import { INSTANCE_DIR, STORE_DIR } from '../../config/path.config';
|
||||||
// inserido por francis inicio
|
|
||||||
import { NotFoundException } from '../../exceptions';
|
import { NotFoundException } from '../../exceptions';
|
||||||
// inserido por francis fim
|
|
||||||
import { dbserver } from '../../libs/db.connect';
|
import { dbserver } from '../../libs/db.connect';
|
||||||
import { RedisCache } from '../../libs/redis.client';
|
import { RedisCache } from '../../libs/redis.client';
|
||||||
import {
|
import {
|
||||||
@@ -66,8 +64,10 @@ export class WAMonitoringService {
|
|||||||
await this.waInstances[instance]?.client?.logout('Log out instance: ' + instance);
|
await this.waInstances[instance]?.client?.logout('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);
|
||||||
|
this.waInstances[instance]?.removeRabbitmqQueues();
|
||||||
delete this.waInstances[instance];
|
delete this.waInstances[instance];
|
||||||
} else {
|
} else {
|
||||||
|
this.waInstances[instance]?.removeRabbitmqQueues();
|
||||||
delete this.waInstances[instance];
|
delete this.waInstances[instance];
|
||||||
this.eventEmitter.emit('remove.instance', instance, 'inner');
|
this.eventEmitter.emit('remove.instance', instance, 'inner');
|
||||||
}
|
}
|
||||||
@@ -75,68 +75,9 @@ export class WAMonitoringService {
|
|||||||
}, 1000 * 60 * time);
|
}, 1000 * 60 * time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* ocultado por francis inicio
|
|
||||||
public async instanceInfo(instanceName?: string) {
|
public async instanceInfo(instanceName?: string) {
|
||||||
this.logger.verbose('get instance info');
|
this.logger.verbose('get instance info');
|
||||||
|
|
||||||
const urlServer = this.configService.get<HttpServer>('SERVER').URL;
|
|
||||||
|
|
||||||
const instances: any[] = await Promise.all(
|
|
||||||
Object.entries(this.waInstances).map(async ([key, value]) => {
|
|
||||||
const status = value?.connectionStatus?.state || 'unknown';
|
|
||||||
|
|
||||||
if (status === 'unknown') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status === 'open') {
|
|
||||||
this.logger.verbose('instance: ' + key + ' - connectionStatus: open');
|
|
||||||
}
|
|
||||||
|
|
||||||
const instanceData: any = {
|
|
||||||
instance: {
|
|
||||||
instanceName: key,
|
|
||||||
owner: value.wuid,
|
|
||||||
profileName: (await value.getProfileName()) || 'not loaded',
|
|
||||||
profilePictureUrl: value.profilePictureUrl,
|
|
||||||
profileStatus: (await value.getProfileStatus()) || '',
|
|
||||||
status: status,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (this.configService.get<Auth>('AUTHENTICATION').EXPOSE_IN_FETCH_INSTANCES) {
|
|
||||||
instanceData.instance.serverUrl = urlServer;
|
|
||||||
instanceData.instance.apikey = (await this.repository.auth.find(key))?.apikey;
|
|
||||||
|
|
||||||
const findChatwoot = await this.waInstances[key].findChatwoot();
|
|
||||||
if (findChatwoot && findChatwoot.enabled) {
|
|
||||||
instanceData.instance.chatwoot = {
|
|
||||||
...findChatwoot,
|
|
||||||
webhook_url: `${urlServer}/chatwoot/webhook/${encodeURIComponent(key)}`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return instanceData;
|
|
||||||
}),
|
|
||||||
).then((results) => results.filter((instance) => instance !== null));
|
|
||||||
|
|
||||||
this.logger.verbose('return instance info: ' + instances.length);
|
|
||||||
|
|
||||||
if (instanceName) {
|
|
||||||
const instance = instances.find((i) => i.instance.instanceName === instanceName);
|
|
||||||
return instance || [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return instances;
|
|
||||||
}
|
|
||||||
|
|
||||||
ocultado por francis fim */
|
|
||||||
|
|
||||||
// inserido por francis inicio
|
|
||||||
|
|
||||||
public async instanceInfo(instanceName?: string) {
|
|
||||||
this.logger.verbose('get instance info');
|
|
||||||
if (instanceName && !this.waInstances[instanceName]) {
|
if (instanceName && !this.waInstances[instanceName]) {
|
||||||
throw new NotFoundException(`Instance "${instanceName}" not found`);
|
throw new NotFoundException(`Instance "${instanceName}" not found`);
|
||||||
}
|
}
|
||||||
@@ -210,17 +151,6 @@ public async instanceInfo(instanceName?: string) {
|
|||||||
return instances.find((i) => i.instance.instanceName === instanceName) ?? instances;
|
return instances.find((i) => i.instance.instanceName === instanceName) ?? instances;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// inserido por francis fim
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private delInstanceFiles() {
|
private delInstanceFiles() {
|
||||||
this.logger.verbose('cron to delete instance files started');
|
this.logger.verbose('cron to delete instance files started');
|
||||||
setInterval(async () => {
|
setInterval(async () => {
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ export class TypebotService {
|
|||||||
const remoteJid = data.remoteJid;
|
const remoteJid = data.remoteJid;
|
||||||
const url = data.url;
|
const url = data.url;
|
||||||
const typebot = data.typebot;
|
const typebot = data.typebot;
|
||||||
|
const startSession = data.startSession;
|
||||||
const variables = data.variables;
|
const variables = data.variables;
|
||||||
const findTypebot = await this.find(instance);
|
const findTypebot = await this.find(instance);
|
||||||
const sessions = (findTypebot.sessions as Session[]) ?? [];
|
const sessions = (findTypebot.sessions as Session[]) ?? [];
|
||||||
@@ -110,12 +111,16 @@ export class TypebotService {
|
|||||||
|
|
||||||
const prefilledVariables = {
|
const prefilledVariables = {
|
||||||
remoteJid: remoteJid,
|
remoteJid: remoteJid,
|
||||||
|
instanceName: instance.instanceName,
|
||||||
};
|
};
|
||||||
|
|
||||||
variables.forEach((variable) => {
|
if (variables?.length) {
|
||||||
|
variables.forEach((variable: { name: string | number; value: string }) => {
|
||||||
prefilledVariables[variable.name] = variable.value;
|
prefilledVariables[variable.name] = variable.value;
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startSession) {
|
||||||
const response = await this.createNewSession(instance, {
|
const response = await this.createNewSession(instance, {
|
||||||
url: url,
|
url: url,
|
||||||
typebot: typebot,
|
typebot: typebot,
|
||||||
@@ -130,13 +135,7 @@ export class TypebotService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (response.sessionId) {
|
if (response.sessionId) {
|
||||||
await this.sendWAMessage(
|
await this.sendWAMessage(instance, remoteJid, response.messages, response.input, response.clientSideActions);
|
||||||
instance,
|
|
||||||
remoteJid,
|
|
||||||
response.messages,
|
|
||||||
response.input,
|
|
||||||
response.clientSideActions,
|
|
||||||
);
|
|
||||||
|
|
||||||
this.waMonitor.waInstances[instance.instanceName].sendDataWebhook(Events.TYPEBOT_START, {
|
this.waMonitor.waInstances[instance.instanceName].sendDataWebhook(Events.TYPEBOT_START, {
|
||||||
remoteJid: remoteJid,
|
remoteJid: remoteJid,
|
||||||
@@ -146,7 +145,35 @@ export class TypebotService {
|
|||||||
sessionId: `${response.sessionId}`,
|
sessionId: `${response.sessionId}`,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Session ID not found in response");
|
throw new Error('Session ID not found in response');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const id = Math.floor(Math.random() * 10000000000).toString();
|
||||||
|
|
||||||
|
const reqData = {
|
||||||
|
startParams: {
|
||||||
|
typebot: data.typebot,
|
||||||
|
prefilledVariables: prefilledVariables,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.waMonitor.waInstances[instance.instanceName].sendDataWebhook(Events.TYPEBOT_START, {
|
||||||
|
remoteJid: remoteJid,
|
||||||
|
url: url,
|
||||||
|
typebot: typebot,
|
||||||
|
variables: variables,
|
||||||
|
sessionId: id,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -201,13 +228,12 @@ export class TypebotService {
|
|||||||
public async createNewSession(instance: InstanceDto, data: any) {
|
public async createNewSession(instance: InstanceDto, data: any) {
|
||||||
const id = Math.floor(Math.random() * 10000000000).toString();
|
const id = Math.floor(Math.random() * 10000000000).toString();
|
||||||
const reqData = {
|
const reqData = {
|
||||||
sessionId: id,
|
|
||||||
startParams: {
|
startParams: {
|
||||||
typebot: data.typebot,
|
typebot: data.typebot,
|
||||||
prefilledVariables: {
|
prefilledVariables: {
|
||||||
...data.prefilledVariables,
|
...data.prefilledVariables,
|
||||||
remoteJid: data.remoteJid,
|
remoteJid: data.remoteJid,
|
||||||
pushName: data.pushName || 'Default Name',
|
pushName: data.pushName || '',
|
||||||
instanceName: instance.instanceName,
|
instanceName: instance.instanceName,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -225,9 +251,9 @@ export class TypebotService {
|
|||||||
prefilledVariables: {
|
prefilledVariables: {
|
||||||
...data.prefilledVariables,
|
...data.prefilledVariables,
|
||||||
remoteJid: data.remoteJid,
|
remoteJid: data.remoteJid,
|
||||||
pushName: data.pushName || 'Default Name',
|
pushName: data.pushName || '',
|
||||||
instanceName: instance.instanceName,
|
instanceName: instance.instanceName,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const typebotData = {
|
const typebotData = {
|
||||||
@@ -435,6 +461,62 @@ export class TypebotService {
|
|||||||
|
|
||||||
await this.sendWAMessage(instance, remoteJid, data.messages, data.input, data.clientSideActions);
|
await this.sendWAMessage(instance, remoteJid, data.messages, data.input, data.clientSideActions);
|
||||||
|
|
||||||
|
if (data.messages.length === 0) {
|
||||||
|
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 (keyword_finish && 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,
|
||||||
|
listening_from_me: listening_from_me,
|
||||||
|
sessions,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.create(instance, typebotData);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const reqData = {
|
||||||
|
message: content,
|
||||||
|
sessionId: data.sessionId,
|
||||||
|
};
|
||||||
|
|
||||||
|
const request = await axios.post(url + '/api/v1/sendMessage', reqData);
|
||||||
|
|
||||||
|
console.log('request', request);
|
||||||
|
await this.sendWAMessage(
|
||||||
|
instance,
|
||||||
|
remoteJid,
|
||||||
|
request.data.messages,
|
||||||
|
request.data.input,
|
||||||
|
request.data.clientSideActions,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -459,6 +541,61 @@ export class TypebotService {
|
|||||||
|
|
||||||
await this.sendWAMessage(instance, remoteJid, data.messages, data.input, data.clientSideActions);
|
await this.sendWAMessage(instance, remoteJid, data.messages, data.input, data.clientSideActions);
|
||||||
|
|
||||||
|
if (data.messages.length === 0) {
|
||||||
|
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 (keyword_finish && 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,
|
||||||
|
listening_from_me: listening_from_me,
|
||||||
|
sessions,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.create(instance, typebotData);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const reqData = {
|
||||||
|
message: content,
|
||||||
|
sessionId: data.sessionId,
|
||||||
|
};
|
||||||
|
|
||||||
|
const request = await axios.post(url + '/api/v1/sendMessage', reqData);
|
||||||
|
|
||||||
|
console.log('request', request);
|
||||||
|
await this.sendWAMessage(
|
||||||
|
instance,
|
||||||
|
remoteJid,
|
||||||
|
request.data.messages,
|
||||||
|
request.data.input,
|
||||||
|
request.data.clientSideActions,
|
||||||
|
);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -500,7 +637,7 @@ export class TypebotService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (content.toLowerCase() === keyword_finish.toLowerCase()) {
|
if (keyword_finish && content.toLowerCase() === keyword_finish.toLowerCase()) {
|
||||||
sessions.splice(sessions.indexOf(session), 1);
|
sessions.splice(sessions.indexOf(session), 1);
|
||||||
|
|
||||||
const typebotData = {
|
const typebotData = {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export class WebhookService {
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return { enabled: false, url: '', events: [], webhook_by_events: false };
|
return { enabled: false, url: '', events: [], webhook_by_events: false, webhook_base64: false };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ import {
|
|||||||
import { Logger } from '../../config/logger.config';
|
import { Logger } from '../../config/logger.config';
|
||||||
import { INSTANCE_DIR, ROOT_DIR } from '../../config/path.config';
|
import { INSTANCE_DIR, ROOT_DIR } from '../../config/path.config';
|
||||||
import { BadRequestException, InternalServerErrorException, NotFoundException } from '../../exceptions';
|
import { BadRequestException, InternalServerErrorException, NotFoundException } from '../../exceptions';
|
||||||
import { getAMQP } from '../../libs/amqp.server';
|
import { getAMQP, removeQueues } from '../../libs/amqp.server';
|
||||||
import { dbserver } from '../../libs/db.connect';
|
import { dbserver } from '../../libs/db.connect';
|
||||||
import { RedisCache } from '../../libs/redis.client';
|
import { RedisCache } from '../../libs/redis.client';
|
||||||
import { getIO } from '../../libs/socket.server';
|
import { getIO } from '../../libs/socket.server';
|
||||||
@@ -276,6 +276,9 @@ export class WAStartupService {
|
|||||||
this.localWebhook.webhook_by_events = data?.webhook_by_events;
|
this.localWebhook.webhook_by_events = data?.webhook_by_events;
|
||||||
this.logger.verbose(`Webhook by events: ${this.localWebhook.webhook_by_events}`);
|
this.logger.verbose(`Webhook by events: ${this.localWebhook.webhook_by_events}`);
|
||||||
|
|
||||||
|
this.localWebhook.webhook_base64 = data?.webhook_base64;
|
||||||
|
this.logger.verbose(`Webhook by webhook_base64: ${this.localWebhook.webhook_base64}`);
|
||||||
|
|
||||||
this.logger.verbose('Webhook loaded');
|
this.logger.verbose('Webhook loaded');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -495,6 +498,14 @@ export class WAStartupService {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async removeRabbitmqQueues() {
|
||||||
|
this.logger.verbose('Removing rabbitmq');
|
||||||
|
|
||||||
|
if (this.localRabbitmq.enabled) {
|
||||||
|
removeQueues(this.instanceName, this.localRabbitmq.events);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async loadTypebot() {
|
private async loadTypebot() {
|
||||||
this.logger.verbose('Loading typebot');
|
this.logger.verbose('Loading typebot');
|
||||||
const data = await this.repository.typebot.find(this.instanceName);
|
const data = await this.repository.typebot.find(this.instanceName);
|
||||||
@@ -1182,7 +1193,7 @@ export class WAStartupService {
|
|||||||
...options,
|
...options,
|
||||||
auth: {
|
auth: {
|
||||||
creds: this.instance.authState.state.creds,
|
creds: this.instance.authState.state.creds,
|
||||||
keys: makeCacheableSignalKeyStore(this.instance.authState.state.keys, P({ level: 'error' })),
|
keys: makeCacheableSignalKeyStore(this.instance.authState.state.keys, P({ level: 'error' }) as any),
|
||||||
},
|
},
|
||||||
logger: P({ level: this.logBaileys }),
|
logger: P({ level: this.logBaileys }),
|
||||||
printQRInTerminal: false,
|
printQRInTerminal: false,
|
||||||
@@ -1240,6 +1251,74 @@ export class WAStartupService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async reloadConnection(): Promise<WASocket> {
|
||||||
|
try {
|
||||||
|
this.instance.authState = await this.defineAuthState();
|
||||||
|
|
||||||
|
const { version } = await fetchLatestBaileysVersion();
|
||||||
|
const session = this.configService.get<ConfigSessionPhone>('CONFIG_SESSION_PHONE');
|
||||||
|
const browser: WABrowserDescription = [session.CLIENT, session.NAME, release()];
|
||||||
|
|
||||||
|
let options;
|
||||||
|
|
||||||
|
if (this.localProxy.enabled) {
|
||||||
|
this.logger.verbose('Proxy enabled');
|
||||||
|
options = {
|
||||||
|
agent: new ProxyAgent(this.localProxy.proxy as any),
|
||||||
|
fetchAgent: new ProxyAgent(this.localProxy.proxy as any),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const socketConfig: UserFacingSocketConfig = {
|
||||||
|
...options,
|
||||||
|
auth: {
|
||||||
|
creds: this.instance.authState.state.creds,
|
||||||
|
keys: makeCacheableSignalKeyStore(this.instance.authState.state.keys, P({ level: 'error' }) as any),
|
||||||
|
},
|
||||||
|
logger: P({ level: this.logBaileys }),
|
||||||
|
printQRInTerminal: false,
|
||||||
|
browser,
|
||||||
|
version,
|
||||||
|
markOnlineOnConnect: this.localSettings.always_online,
|
||||||
|
connectTimeoutMs: 60_000,
|
||||||
|
qrTimeout: 40_000,
|
||||||
|
defaultQueryTimeoutMs: undefined,
|
||||||
|
emitOwnEvents: false,
|
||||||
|
msgRetryCounterCache: this.msgRetryCounterCache,
|
||||||
|
getMessage: async (key) => (await this.getMessage(key)) as Promise<proto.IMessage>,
|
||||||
|
generateHighQualityLinkPreview: true,
|
||||||
|
syncFullHistory: true,
|
||||||
|
userDevicesCache: this.userDevicesCache,
|
||||||
|
transactionOpts: { maxCommitRetries: 1, delayBetweenTriesMs: 10 },
|
||||||
|
patchMessageBeforeSending: (message) => {
|
||||||
|
const requiresPatch = !!(message.buttonsMessage || message.listMessage || message.templateMessage);
|
||||||
|
if (requiresPatch) {
|
||||||
|
message = {
|
||||||
|
viewOnceMessageV2: {
|
||||||
|
message: {
|
||||||
|
messageContextInfo: {
|
||||||
|
deviceListMetadataVersion: 2,
|
||||||
|
deviceListMetadata: {},
|
||||||
|
},
|
||||||
|
...message,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return message;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
this.client = makeWASocket(socketConfig);
|
||||||
|
|
||||||
|
return this.client;
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error(error);
|
||||||
|
throw new InternalServerErrorException(error?.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private readonly chatHandle = {
|
private readonly chatHandle = {
|
||||||
'chats.upsert': async (chats: Chat[], database: Database) => {
|
'chats.upsert': async (chats: Chat[], database: Database) => {
|
||||||
this.logger.verbose('Event received: chats.upsert');
|
this.logger.verbose('Event received: chats.upsert');
|
||||||
@@ -1452,7 +1531,36 @@ export class WAStartupService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const messageRaw: MessageRaw = {
|
let messageRaw: MessageRaw;
|
||||||
|
|
||||||
|
if (
|
||||||
|
(this.localWebhook.webhook_base64 === true && received?.message.documentMessage) ||
|
||||||
|
received?.message.imageMessage
|
||||||
|
) {
|
||||||
|
const buffer = await downloadMediaMessage(
|
||||||
|
{ key: received.key, message: received?.message },
|
||||||
|
'buffer',
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
logger: P({ level: 'error' }) as any,
|
||||||
|
reuploadRequest: this.client.updateMediaMessage,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
console.log(buffer);
|
||||||
|
messageRaw = {
|
||||||
|
key: received.key,
|
||||||
|
pushName: received.pushName,
|
||||||
|
message: {
|
||||||
|
...received.message,
|
||||||
|
base64: buffer ? buffer.toString('base64') : undefined,
|
||||||
|
},
|
||||||
|
messageType: getContentType(received.message),
|
||||||
|
messageTimestamp: received.messageTimestamp as number,
|
||||||
|
owner: this.instance.name,
|
||||||
|
source: getDevice(received.key.id),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
messageRaw = {
|
||||||
key: received.key,
|
key: received.key,
|
||||||
pushName: received.pushName,
|
pushName: received.pushName,
|
||||||
message: { ...received.message },
|
message: { ...received.message },
|
||||||
@@ -1461,6 +1569,7 @@ export class WAStartupService {
|
|||||||
owner: this.instance.name,
|
owner: this.instance.name,
|
||||||
source: getDevice(received.key.id),
|
source: getDevice(received.key.id),
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (this.localSettings.read_messages && received.key.id !== 'status@broadcast') {
|
if (this.localSettings.read_messages && received.key.id !== 'status@broadcast') {
|
||||||
await this.client.readMessages([received.key]);
|
await this.client.readMessages([received.key]);
|
||||||
@@ -1952,7 +2061,12 @@ export class WAStartupService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async sendMessageWithTyping<T = proto.IMessage>(number: string, message: T, options?: Options) {
|
private async sendMessageWithTyping<T = proto.IMessage>(
|
||||||
|
number: string,
|
||||||
|
message: T,
|
||||||
|
options?: Options,
|
||||||
|
isChatwoot = false,
|
||||||
|
) {
|
||||||
this.logger.verbose('Sending message with typing');
|
this.logger.verbose('Sending message with typing');
|
||||||
|
|
||||||
this.logger.verbose(`Check if number "${number}" is WhatsApp`);
|
this.logger.verbose(`Check if number "${number}" is WhatsApp`);
|
||||||
@@ -2110,7 +2224,7 @@ export class WAStartupService {
|
|||||||
this.logger.verbose('Sending data to webhook in event SEND_MESSAGE');
|
this.logger.verbose('Sending data to webhook in event SEND_MESSAGE');
|
||||||
await this.sendDataWebhook(Events.SEND_MESSAGE, messageRaw);
|
await this.sendDataWebhook(Events.SEND_MESSAGE, messageRaw);
|
||||||
|
|
||||||
if (this.localChatwoot.enabled) {
|
if (this.localChatwoot.enabled && !isChatwoot) {
|
||||||
this.chatwootService.eventWhatsapp(Events.SEND_MESSAGE, { instanceName: this.instance.name }, messageRaw);
|
this.chatwootService.eventWhatsapp(Events.SEND_MESSAGE, { instanceName: this.instance.name }, messageRaw);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2135,7 +2249,7 @@ export class WAStartupService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send Message Controller
|
// Send Message Controller
|
||||||
public async textMessage(data: SendTextDto) {
|
public async textMessage(data: SendTextDto, isChatwoot = false) {
|
||||||
this.logger.verbose('Sending text message');
|
this.logger.verbose('Sending text message');
|
||||||
return await this.sendMessageWithTyping(
|
return await this.sendMessageWithTyping(
|
||||||
data.number,
|
data.number,
|
||||||
@@ -2143,6 +2257,7 @@ export class WAStartupService {
|
|||||||
conversation: data.textMessage.text,
|
conversation: data.textMessage.text,
|
||||||
},
|
},
|
||||||
data?.options,
|
data?.options,
|
||||||
|
isChatwoot,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2308,36 +2423,22 @@ export class WAStartupService {
|
|||||||
mediaMessage.fileName = arrayMatch[1];
|
mediaMessage.fileName = arrayMatch[1];
|
||||||
this.logger.verbose('File name: ' + mediaMessage.fileName);
|
this.logger.verbose('File name: ' + mediaMessage.fileName);
|
||||||
}
|
}
|
||||||
// *inserido francis inicio
|
|
||||||
let mimetype: string;
|
|
||||||
// *inserido francis final
|
|
||||||
|
|
||||||
|
|
||||||
if (mediaMessage.mediatype === 'image' && !mediaMessage.fileName) {
|
if (mediaMessage.mediatype === 'image' && !mediaMessage.fileName) {
|
||||||
mediaMessage.fileName = 'image.png';
|
mediaMessage.fileName = 'image.png';
|
||||||
// inserido francis inicio
|
|
||||||
mimetype = 'image/png';
|
|
||||||
// inserido francis inicio
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mediaMessage.mediatype === 'video' && !mediaMessage.fileName) {
|
if (mediaMessage.mediatype === 'video' && !mediaMessage.fileName) {
|
||||||
mediaMessage.fileName = 'video.mp4';
|
mediaMessage.fileName = 'video.mp4';
|
||||||
// inserido francis inicio
|
|
||||||
mimetype = 'video/mp4';
|
|
||||||
// inserido francis final
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ocultado francis inicio
|
let mimetype: string;
|
||||||
// let mimetype: string;
|
|
||||||
|
|
||||||
|
if (isURL(mediaMessage.media)) {
|
||||||
// if (isURL(mediaMessage.media)) {
|
mimetype = getMIMEType(mediaMessage.media);
|
||||||
// mimetype = getMIMEType(mediaMessage.media);
|
} else {
|
||||||
// } else {
|
mimetype = getMIMEType(mediaMessage.fileName);
|
||||||
// mimetype = getMIMEType(mediaMessage.fileName);
|
}
|
||||||
// }
|
|
||||||
// ocultado francis final
|
|
||||||
|
|
||||||
this.logger.verbose('Mimetype: ' + mimetype);
|
this.logger.verbose('Mimetype: ' + mimetype);
|
||||||
|
|
||||||
@@ -2433,11 +2534,11 @@ export class WAStartupService {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async mediaMessage(data: SendMediaDto) {
|
public async mediaMessage(data: SendMediaDto, isChatwoot = false) {
|
||||||
this.logger.verbose('Sending media message');
|
this.logger.verbose('Sending media message');
|
||||||
const generate = await this.prepareMediaMessage(data.mediaMessage);
|
const generate = await this.prepareMediaMessage(data.mediaMessage);
|
||||||
|
|
||||||
return await this.sendMessageWithTyping(data.number, { ...generate.message }, data?.options);
|
return await this.sendMessageWithTyping(data.number, { ...generate.message }, data?.options, isChatwoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async processAudio(audio: string, number: string) {
|
public async processAudio(audio: string, number: string) {
|
||||||
@@ -2494,7 +2595,7 @@ export class WAStartupService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async audioWhatsapp(data: SendAudioDto) {
|
public async audioWhatsapp(data: SendAudioDto, isChatwoot = false) {
|
||||||
this.logger.verbose('Sending audio whatsapp');
|
this.logger.verbose('Sending audio whatsapp');
|
||||||
|
|
||||||
if (!data.options?.encoding && data.options?.encoding !== false) {
|
if (!data.options?.encoding && data.options?.encoding !== false) {
|
||||||
@@ -2513,6 +2614,7 @@ export class WAStartupService {
|
|||||||
mimetype: 'audio/mp4',
|
mimetype: 'audio/mp4',
|
||||||
},
|
},
|
||||||
{ presence: 'recording', delay: data?.options?.delay },
|
{ presence: 'recording', delay: data?.options?.delay },
|
||||||
|
isChatwoot,
|
||||||
);
|
);
|
||||||
|
|
||||||
fs.unlinkSync(convert);
|
fs.unlinkSync(convert);
|
||||||
@@ -2534,6 +2636,7 @@ export class WAStartupService {
|
|||||||
mimetype: 'audio/ogg; codecs=opus',
|
mimetype: 'audio/ogg; codecs=opus',
|
||||||
},
|
},
|
||||||
{ presence: 'recording', delay: data?.options?.delay },
|
{ presence: 'recording', delay: data?.options?.delay },
|
||||||
|
isChatwoot,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2714,6 +2817,7 @@ export class WAStartupService {
|
|||||||
|
|
||||||
public async markMessageAsRead(data: ReadMessageDto) {
|
public async markMessageAsRead(data: ReadMessageDto) {
|
||||||
this.logger.verbose('Marking message as read');
|
this.logger.verbose('Marking message as read');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const keys: proto.IMessageKey[] = [];
|
const keys: proto.IMessageKey[] = [];
|
||||||
data.read_messages.forEach((read) => {
|
data.read_messages.forEach((read) => {
|
||||||
@@ -2843,7 +2947,7 @@ export class WAStartupService {
|
|||||||
'buffer',
|
'buffer',
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
logger: P({ level: 'error' }),
|
logger: P({ level: 'error' }) as any,
|
||||||
reuploadRequest: this.client.updateMediaMessage,
|
reuploadRequest: this.client.updateMediaMessage,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ export declare namespace wa {
|
|||||||
url?: string;
|
url?: string;
|
||||||
events?: string[];
|
events?: string[];
|
||||||
webhook_by_events?: boolean;
|
webhook_by_events?: boolean;
|
||||||
|
webhook_base64?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type LocalChatwoot = {
|
export type LocalChatwoot = {
|
||||||
|
|||||||
110
views/manager-wip.hbs
Normal file
110
views/manager-wip.hbs
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="pt-br">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link rel="shortcut icon" href="https://evolution-api.com/files/evolution-api-favicon.png" type="image/x-icon">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css"
|
||||||
|
integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous">
|
||||||
|
<title>Instance Manager</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="container mt-4">
|
||||||
|
<!-- Botão para abrir o modal de adicionar nova instância -->
|
||||||
|
<button class="btn btn-primary mb-3" data-toggle="modal" data-target="#actionModal" data-action="add">Nova
|
||||||
|
Instância</button>
|
||||||
|
|
||||||
|
<!-- Tabela de instâncias -->
|
||||||
|
<table class="table table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Nome da Instância</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>API Key</th>
|
||||||
|
<th>Ações</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<!-- Iterando sobre as instâncias e preenchendo a tabela -->
|
||||||
|
{{#each instances}}
|
||||||
|
<tr>
|
||||||
|
<td>{{this.instance.instanceName}}</td>
|
||||||
|
<td>{{this.instance.status}}</td>
|
||||||
|
<td>{{this.instance.apikey}}</td>
|
||||||
|
<td>
|
||||||
|
<!-- Dropdown de ações para cada instância -->
|
||||||
|
<div class="dropdown">
|
||||||
|
<button class="btn btn-secondary dropdown-toggle" type="button" id="actionDropdown"
|
||||||
|
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
Ações
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-menu" aria-labelledby="actionDropdown">
|
||||||
|
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#actionModal"
|
||||||
|
data-action="connect">Connect</a>
|
||||||
|
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#actionModal"
|
||||||
|
data-action="restart">Restart</a>
|
||||||
|
<!-- Adicione mais itens de ação aqui -->
|
||||||
|
<!-- ... -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{/each}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Modal de ações -->
|
||||||
|
<div class="modal fade" id="actionModal" tabindex="-1" role="dialog" aria-labelledby="actionModalLabel"
|
||||||
|
aria-hidden="true">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="actionModalLabel">Ação</h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Fechar</button>
|
||||||
|
<button type="button" class="btn btn-primary">Salvar</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"
|
||||||
|
integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"
|
||||||
|
integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN"
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.min.js"
|
||||||
|
integrity="sha384-+sLIOodYLS7CIrQpBjl+C7nPvqq+FbNUBDunl/OZv93DB7Ln/533i8e/mZXLi/P+"
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(document).ready(function(){
|
||||||
|
$('#actionModal').on('show.bs.modal', function(event) {
|
||||||
|
var button = $(event.relatedTarget);
|
||||||
|
var action = button.data('action');
|
||||||
|
|
||||||
|
console.log(action);
|
||||||
|
|
||||||
|
if (action === 'connect') {
|
||||||
|
|
||||||
|
} else if (action === 'restart') {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<iframe src="https://app.smith.dgcode.com.br/app/evolutionapi-public/home-64ca60783615e270291978b4?embed=true" frameborder="0" style="width: 100%; height: 100vh;"></iframe>
|
<iframe src="https://manager.evolution-api.com" frameborder="0" style="width: 100%; height: 100vh;"></iframe>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user