diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dd59c0d..7429fddc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +# 1.4.2 (2023-07-24 20:52) + +### Fixed + +* Fixed validation is set settings +* Adjusts in group validations +* Ajusts in sticker message to chatwoot + # 1.4.1 (2023-07-24 18:28) ### Fixed diff --git a/package.json b/package.json index 1145676d..6489b86c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "evolution-api", - "version": "1.4.1", + "version": "1.4.2", "description": "Rest api for communication with WhatsApp", "main": "./dist/src/main.js", "scripts": { diff --git a/src/validate/validate.schema.ts b/src/validate/validate.schema.ts index aea723ca..3c1f8d0a 100644 --- a/src/validate/validate.schema.ts +++ b/src/validate/validate.schema.ts @@ -667,6 +667,7 @@ export const createGroupSchema: JSONSchema7 = { subject: { type: 'string' }, description: { type: 'string' }, profilePicture: { type: 'string' }, + promoteParticipants: { type: 'boolean', enum: [true, false] }, participants: { type: 'array', minItems: 1, diff --git a/src/whatsapp/controllers/instance.controller.ts b/src/whatsapp/controllers/instance.controller.ts index 7322e194..e9e690b3 100644 --- a/src/whatsapp/controllers/instance.controller.ts +++ b/src/whatsapp/controllers/instance.controller.ts @@ -41,77 +41,136 @@ export class InstanceController { chatwoot_url, chatwoot_sign_msg, }: InstanceDto) { - this.logger.verbose('requested createInstance from ' + instanceName + ' instance'); + try { + 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'); - await this.authService.checkDuplicateToken(token); - - this.logger.verbose('creating instance'); - const instance = new WAStartupService( - this.configService, - this.eventEmitter, - this.repository, - this.cache, - ); - instance.instanceName = instanceName - .toLowerCase() - .replace(/[^a-z0-9]/g, '') - .replace(' ', ''); - - this.logger.verbose('instance: ' + instance.instanceName + ' created'); - - this.waMonitor.waInstances[instance.instanceName] = instance; - this.waMonitor.delInstanceTime(instance.instanceName); - - this.logger.verbose('generating hash'); - const hash = await this.authService.generateHash( - { - instanceName: instance.instanceName, - }, - token, - ); - - this.logger.verbose('hash: ' + hash + ' generated'); - - let getEvents: string[]; - - if (webhook) { - if (!isURL(webhook, { require_tld: false })) { - throw new BadRequestException('Invalid "url" property in webhook'); + 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('creating webhook'); - try { - this.webhookService.create(instance, { - enabled: true, - url: webhook, - events, + this.logger.verbose('checking duplicate token'); + await this.authService.checkDuplicateToken(token); + + this.logger.verbose('creating instance'); + const instance = new WAStartupService( + this.configService, + this.eventEmitter, + this.repository, + this.cache, + ); + instance.instanceName = instanceName + .toLowerCase() + .replace(/[^a-z0-9]/g, '') + .replace(' ', ''); + + this.logger.verbose('instance: ' + instance.instanceName + ' created'); + + this.waMonitor.waInstances[instance.instanceName] = instance; + this.waMonitor.delInstanceTime(instance.instanceName); + + this.logger.verbose('generating hash'); + const hash = await this.authService.generateHash( + { + instanceName: instance.instanceName, + }, + token, + ); + + this.logger.verbose('hash: ' + hash + ' generated'); + + let getEvents: string[]; + + if (webhook) { + if (!isURL(webhook, { require_tld: false })) { + throw new BadRequestException('Invalid "url" property in webhook'); + } + + this.logger.verbose('creating webhook'); + try { + this.webhookService.create(instance, { + enabled: true, + url: webhook, + events, + webhook_by_events, + }); + + getEvents = (await this.webhookService.find(instance)).events; + } catch (error) { + this.logger.log(error); + } + } + + if (!chatwoot_account_id || !chatwoot_token || !chatwoot_url) { + let getQrcode: wa.QrCode; + + if (qrcode) { + this.logger.verbose('creating qrcode'); + await instance.connectToWhatsapp(number); + await delay(5000); + getQrcode = instance.qrCode; + } + + const result = { + instance: { + instanceName: instance.instanceName, + status: 'created', + }, + hash, + webhook, webhook_by_events, + events: getEvents, + qrcode: getQrcode, + }; + + this.logger.verbose('instance created'); + this.logger.verbose(result); + + return result; + } + + if (!chatwoot_account_id) { + throw new BadRequestException('account_id is required'); + } + + if (!chatwoot_token) { + throw new BadRequestException('token is required'); + } + + if (!chatwoot_url) { + throw new BadRequestException('url is required'); + } + + if (!isURL(chatwoot_url, { require_tld: false })) { + throw new BadRequestException('Invalid "url" property in chatwoot'); + } + + const urlServer = this.configService.get('SERVER').URL; + + try { + this.chatwootService.create(instance, { + enabled: true, + account_id: chatwoot_account_id, + token: chatwoot_token, + url: chatwoot_url, + sign_msg: chatwoot_sign_msg || false, + name_inbox: instance.instanceName, + number, }); - getEvents = (await this.webhookService.find(instance)).events; + this.chatwootService.initInstanceChatwoot( + instance, + instance.instanceName, + `${urlServer}/chatwoot/webhook/${instance.instanceName}`, + qrcode, + number, + ); } catch (error) { this.logger.log(error); } - } - if (!chatwoot_account_id || !chatwoot_token || !chatwoot_url) { - let getQrcode: wa.QrCode; - - if (qrcode) { - this.logger.verbose('creating qrcode'); - await instance.connectToWhatsapp(number); - await delay(5000); - getQrcode = instance.qrCode; - } - - const result = { + return { instance: { instanceName: instance.instanceName, status: 'created', @@ -120,75 +179,21 @@ export class InstanceController { webhook, webhook_by_events, events: getEvents, - qrcode: getQrcode, + chatwoot: { + enabled: true, + account_id: chatwoot_account_id, + token: chatwoot_token, + url: chatwoot_url, + sign_msg: chatwoot_sign_msg || false, + number, + name_inbox: instance.instanceName, + webhook_url: `${urlServer}/chatwoot/webhook/${instance.instanceName}`, + }, }; - - this.logger.verbose('instance created'); - this.logger.verbose(result); - - return result; - } - - if (!chatwoot_account_id) { - throw new BadRequestException('account_id is required'); - } - - if (!chatwoot_token) { - throw new BadRequestException('token is required'); - } - - if (!chatwoot_url) { - throw new BadRequestException('url is required'); - } - - if (!isURL(chatwoot_url, { require_tld: false })) { - throw new BadRequestException('Invalid "url" property in chatwoot'); - } - - const urlServer = this.configService.get('SERVER').URL; - - try { - this.chatwootService.create(instance, { - enabled: true, - account_id: chatwoot_account_id, - token: chatwoot_token, - url: chatwoot_url, - sign_msg: chatwoot_sign_msg || false, - name_inbox: instance.instanceName, - number, - }); - - this.chatwootService.initInstanceChatwoot( - instance, - instance.instanceName, - `${urlServer}/chatwoot/webhook/${instance.instanceName}`, - qrcode, - number, - ); } catch (error) { - this.logger.log(error); + console.log(error); + return { error: true, message: error.toString() }; } - - return { - instance: { - instanceName: instance.instanceName, - status: 'created', - }, - hash, - webhook, - webhook_by_events, - events: getEvents, - chatwoot: { - enabled: true, - account_id: chatwoot_account_id, - token: chatwoot_token, - url: chatwoot_url, - sign_msg: chatwoot_sign_msg || false, - number, - name_inbox: instance.instanceName, - webhook_url: `${urlServer}/chatwoot/webhook/${instance.instanceName}`, - }, - }; } public async connectToWhatsapp({ instanceName, number = null }: InstanceDto) { diff --git a/src/whatsapp/controllers/settings.controller.ts b/src/whatsapp/controllers/settings.controller.ts index 59031634..f538abe6 100644 --- a/src/whatsapp/controllers/settings.controller.ts +++ b/src/whatsapp/controllers/settings.controller.ts @@ -15,10 +15,6 @@ export class SettingsController { 'requested createSettings from ' + instance.instanceName + ' instance', ); - if (data.reject_call && data.msg_call.trim() == '') { - throw new BadRequestException('msg_call is required'); - } - return this.settingsService.create(instance, data); } diff --git a/src/whatsapp/dto/group.dto.ts b/src/whatsapp/dto/group.dto.ts index bc36e27f..6dfdc45c 100644 --- a/src/whatsapp/dto/group.dto.ts +++ b/src/whatsapp/dto/group.dto.ts @@ -1,7 +1,8 @@ export class CreateGroupDto { subject: string; - description?: string; participants: string[]; + description?: string; + promoteParticipants?: boolean; } export class GroupPictureDto { diff --git a/src/whatsapp/repository/repository.manager.ts b/src/whatsapp/repository/repository.manager.ts index dde636c7..d506cc46 100644 --- a/src/whatsapp/repository/repository.manager.ts +++ b/src/whatsapp/repository/repository.manager.ts @@ -102,7 +102,12 @@ export class RepositoryBroker { this.logger.verbose('creating store path: ' + storePath); const tempDir = join(storePath, 'temp'); + const chatwootDir = join(storePath, 'chatwoot'); + if (!fs.existsSync(chatwootDir)) { + this.logger.verbose('creating chatwoot dir: ' + chatwootDir); + fs.mkdirSync(chatwootDir, { recursive: true }); + } if (!fs.existsSync(tempDir)) { this.logger.verbose('creating temp dir: ' + tempDir); fs.mkdirSync(tempDir, { recursive: true }); diff --git a/src/whatsapp/services/chatwoot.service.ts b/src/whatsapp/services/chatwoot.service.ts index c77162ad..6e55d145 100644 --- a/src/whatsapp/services/chatwoot.service.ts +++ b/src/whatsapp/services/chatwoot.service.ts @@ -1179,7 +1179,7 @@ export class ChatwootService { videoMessage: msg.videoMessage?.caption, extendedTextMessage: msg.extendedTextMessage?.text, messageContextInfo: msg.messageContextInfo?.stanzaId, - stickerMessage: msg.stickerMessage?.fileSha256.toString('base64'), + stickerMessage: undefined, documentMessage: msg.documentMessage?.caption, documentWithCaptionMessage: msg.documentWithCaptionMessage?.message?.documentMessage?.caption, @@ -1199,10 +1199,6 @@ export class ChatwootService { const result = typeKey ? types[typeKey] : undefined; - if (typeKey === 'stickerMessage') { - return null; - } - if (typeKey === 'contactMessage') { const vCardData = result.split('\n'); const contactInfo = {}; diff --git a/src/whatsapp/services/whatsapp.service.ts b/src/whatsapp/services/whatsapp.service.ts index 6c7c96f0..ff6fdd71 100644 --- a/src/whatsapp/services/whatsapp.service.ts +++ b/src/whatsapp/services/whatsapp.service.ts @@ -116,16 +116,15 @@ import { useMultiFileAuthStateDb } from '../../utils/use-multi-file-auth-state-d import Long from 'long'; import { WebhookRaw } from '../models/webhook.model'; import { ChatwootRaw } from '../models/chatwoot.model'; +import { SettingsRaw } from '../models'; import { dbserver } from '../../db/db.connect'; import NodeCache from 'node-cache'; import { useMultiFileAuthStateRedisDb } from '../../utils/use-multi-file-auth-state-redis-db'; import sharp from 'sharp'; import { RedisCache } from '../../db/redis.client'; import { Log } from '../../config/env.config'; -import ProxyAgent from 'proxy-agent'; import { ChatwootService } from './chatwoot.service'; import { waMonitor } from '../whatsapp.module'; -import { SettingsRaw } from '../models'; export class WAStartupService { constructor( @@ -382,7 +381,7 @@ export class WAStartupService { if (!data) { this.logger.verbose('Settings not found'); - throw new NotFoundException('Settings not found'); + return null; } this.logger.verbose(`Settings url: ${data.reject_call}`); @@ -1129,7 +1128,7 @@ export class WAStartupService { received.messageTimestamp = received.messageTimestamp?.toNumber(); } - if (settings.groups_ignore && received.key.remoteJid.includes('@g.us')) { + if (settings?.groups_ignore && received.key.remoteJid.includes('@g.us')) { this.logger.verbose('group ignored'); return; } @@ -1517,7 +1516,7 @@ export class WAStartupService { .split(/\:/)[0] .split('@')[0]; - if (number.length >= 18) { + if (number.includes('-') && number.length >= 24) { this.logger.verbose('Jid created is group: ' + `${number}@g.us`); number = number.replace(/[^\d-]/g, ''); return `${number}@g.us`; @@ -1525,6 +1524,12 @@ export class WAStartupService { number = number.replace(/\D/g, ''); + if (number.length >= 18) { + this.logger.verbose('Jid created is group: ' + `${number}@g.us`); + number = number.replace(/[^\d-]/g, ''); + return `${number}@g.us`; + } + this.logger.verbose('Jid created is whatsapp: ' + `${number}@s.whatsapp.net`); return `${number}@s.whatsapp.net`; } @@ -1686,20 +1691,13 @@ export class WAStartupService { if (options?.mentions) { this.logger.verbose('Mentions defined'); - if ( - !Array.isArray(options.mentions.mentioned) && - !options.mentions.everyOne - ) { - throw new BadRequestException('Mentions must be an array'); - } - - if (options.mentions.everyOne) { + if (options.mentions?.everyOne) { this.logger.verbose('Mentions everyone'); this.logger.verbose('Getting group metadata'); mentions = groupMetadata.participants.map((participant) => participant.id); this.logger.verbose('Getting group metadata for mentions'); - } else { + } else if (options.mentions?.mentioned?.length) { this.logger.verbose('Mentions manually defined'); mentions = options.mentions.mentioned.map((mention) => { const jid = this.createJid(mention); @@ -2782,10 +2780,19 @@ export class WAStartupService { await this.client.groupUpdateDescription(id, create.description); } + if (create?.promoteParticipants) { + this.logger.verbose('Prometing group participants: ' + create.description); + await this.updateGParticipant({ + groupJid: id, + action: 'promote', + participants: participants, + }); + } + const group = await this.client.groupMetadata(id); this.logger.verbose('Getting group metadata'); - return { groupMetadata: group }; + return group; } catch (error) { this.logger.error(error); throw new InternalServerErrorException('Error creating group', error.toString());