From ee0f0f0be0457119e33d98aa055cb93ddbe3731b Mon Sep 17 00:00:00 2001 From: Gabriel Pastori <58153955+gabrielpastori1@users.noreply.github.com> Date: Wed, 6 Dec 2023 00:31:35 -0300 Subject: [PATCH 1/3] add send presence router --- src/validate/validate.schema.ts | 10 ++++++ .../controllers/sendMessage.controller.ts | 6 ++++ src/whatsapp/dto/sendMessage.dto.ts | 9 +++++ src/whatsapp/routers/sendMessage.router.ts | 18 ++++++++++ src/whatsapp/services/whatsapp.service.ts | 33 +++++++++++++++++++ 5 files changed, 76 insertions(+) diff --git a/src/validate/validate.schema.ts b/src/validate/validate.schema.ts index 9781e18c..4fad3269 100644 --- a/src/validate/validate.schema.ts +++ b/src/validate/validate.schema.ts @@ -149,6 +149,16 @@ export const textMessageSchema: JSONSchema7 = { required: ['textMessage', 'number'], }; +export const presenceSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + number: { ...numberDefinition }, + options: { ...optionsSchema, required: ['presence', 'delay'] }, + }, + required: ['options', 'number'], +}; + export const pollMessageSchema: JSONSchema7 = { $id: v4(), type: 'object', diff --git a/src/whatsapp/controllers/sendMessage.controller.ts b/src/whatsapp/controllers/sendMessage.controller.ts index 20e38ae5..a6b844dc 100644 --- a/src/whatsapp/controllers/sendMessage.controller.ts +++ b/src/whatsapp/controllers/sendMessage.controller.ts @@ -11,6 +11,7 @@ import { SendLocationDto, SendMediaDto, SendPollDto, + SendPresenceDto, SendReactionDto, SendStatusDto, SendStickerDto, @@ -23,6 +24,11 @@ const logger = new Logger('MessageRouter'); export class SendMessageController { constructor(private readonly waMonitor: WAMonitoringService) {} + public async sendPresence({ instanceName }: InstanceDto, data: SendPresenceDto) { + logger.verbose('requested sendPresence from ' + instanceName + ' instance'); + return await this.waMonitor.waInstances[instanceName].sendPresence(data); + } + public async sendText({ instanceName }: InstanceDto, data: SendTextDto) { logger.verbose('requested sendText from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].textMessage(data); diff --git a/src/whatsapp/dto/sendMessage.dto.ts b/src/whatsapp/dto/sendMessage.dto.ts index e0d6d8f9..8cc4dd1e 100644 --- a/src/whatsapp/dto/sendMessage.dto.ts +++ b/src/whatsapp/dto/sendMessage.dto.ts @@ -46,9 +46,18 @@ class PollMessage { values: string[]; messageSecret?: Uint8Array; } +export class SendPresenceDto extends Metadata { + options: { + presence: WAPresence; + delay: number; + }; +} export class SendTextDto extends Metadata { textMessage: TextMessage; } +export class SendPresence extends Metadata { + textMessage: TextMessage; +} export class SendStatusDto extends Metadata { statusMessage: StatusMessage; diff --git a/src/whatsapp/routers/sendMessage.router.ts b/src/whatsapp/routers/sendMessage.router.ts index d87db44d..02047249 100644 --- a/src/whatsapp/routers/sendMessage.router.ts +++ b/src/whatsapp/routers/sendMessage.router.ts @@ -9,6 +9,7 @@ import { locationMessageSchema, mediaMessageSchema, pollMessageSchema, + presenceSchema, reactionMessageSchema, statusMessageSchema, stickerMessageSchema, @@ -23,6 +24,7 @@ import { SendLocationDto, SendMediaDto, SendPollDto, + SendPresenceDto, SendReactionDto, SendStatusDto, SendStickerDto, @@ -37,6 +39,22 @@ export class MessageRouter extends RouterBroker { constructor(...guards: RequestHandler[]) { super(); this.router + .post(this.routerPath('sendPresence'), ...guards, async (req, res) => { + logger.verbose('request received in sendText'); + logger.verbose('request body: '); + logger.verbose(req.body); + + logger.verbose('request query: '); + logger.verbose(req.query); + const response = await this.dataValidate({ + request: req, + schema: presenceSchema, + ClassRef: SendPresenceDto, + execute: (instance, data) => sendMessageController.sendPresence(instance, data), + }); + + return res.status(HttpStatus.CREATED).json(response); + }) .post(this.routerPath('sendText'), ...guards, async (req, res) => { logger.verbose('request received in sendText'); logger.verbose('request body: '); diff --git a/src/whatsapp/services/whatsapp.service.ts b/src/whatsapp/services/whatsapp.service.ts index 5c3edc44..83df4b74 100644 --- a/src/whatsapp/services/whatsapp.service.ts +++ b/src/whatsapp/services/whatsapp.service.ts @@ -109,6 +109,7 @@ import { SendLocationDto, SendMediaDto, SendPollDto, + SendPresenceDto, SendReactionDto, SendStatusDto, SendStickerDto, @@ -2387,6 +2388,38 @@ export class WAStartupService { return this.stateConnection; } + public async sendPresence(data: SendPresenceDto) { + try { + const { number } = data; + + this.logger.verbose(`Check if number "${number}" is WhatsApp`); + const isWA = (await this.whatsappNumber({ numbers: [number] }))?.shift(); + + this.logger.verbose(`Exists: "${isWA.exists}" | jid: ${isWA.jid}`); + if (!isWA.exists && !isJidGroup(isWA.jid) && !isWA.jid.includes('@broadcast')) { + throw new BadRequestException(isWA); + } + + const sender = isWA.jid; + + this.logger.verbose('Sending presence'); + await this.client.presenceSubscribe(sender); + this.logger.verbose('Subscribing to presence'); + + await this.client.sendPresenceUpdate(data.options?.presence ?? 'composing', sender); + this.logger.verbose('Sending presence update: ' + data.options?.presence ?? 'composing'); + + await delay(data.options.delay); + this.logger.verbose('Set delay: ' + data.options.delay); + + await this.client.sendPresenceUpdate('paused', sender); + this.logger.verbose('Sending presence update: paused'); + } catch (error) { + this.logger.error(error); + throw new BadRequestException(error.toString()); + } + } + // Send Message Controller public async textMessage(data: SendTextDto, isChatwoot = false) { this.logger.verbose('Sending text message'); From 4222c0e53bdb2ef0a9022dc3f222eb8369d52ed5 Mon Sep 17 00:00:00 2001 From: Gabriel Pastori <58153955+gabrielpastori1@users.noreply.github.com> Date: Wed, 6 Dec 2023 00:32:27 -0300 Subject: [PATCH 2/3] Fix logger message in sendPresence route --- src/whatsapp/routers/sendMessage.router.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/whatsapp/routers/sendMessage.router.ts b/src/whatsapp/routers/sendMessage.router.ts index 02047249..79fedbe2 100644 --- a/src/whatsapp/routers/sendMessage.router.ts +++ b/src/whatsapp/routers/sendMessage.router.ts @@ -40,7 +40,7 @@ export class MessageRouter extends RouterBroker { super(); this.router .post(this.routerPath('sendPresence'), ...guards, async (req, res) => { - logger.verbose('request received in sendText'); + logger.verbose('request received in sendPresence'); logger.verbose('request body: '); logger.verbose(req.body); From 42dd280aca536721955da120c8afaae8453c3e55 Mon Sep 17 00:00:00 2001 From: Gabriel Pastori <58153955+gabrielpastori1@users.noreply.github.com> Date: Fri, 8 Dec 2023 18:40:48 -0300 Subject: [PATCH 3/3] change sendPresence from sendMessage to chat --- .vscode/settings.json | 4 ++-- src/whatsapp/controllers/chat.controller.ts | 6 ++++++ .../controllers/sendMessage.controller.ts | 6 ------ src/whatsapp/dto/chat.dto.ts | 19 ++++++++++++++++++- src/whatsapp/dto/sendMessage.dto.ts | 7 +------ src/whatsapp/routers/chat.router.ts | 18 ++++++++++++++++++ src/whatsapp/routers/sendMessage.router.ts | 18 ------------------ src/whatsapp/services/whatsapp.service.ts | 2 +- 8 files changed, 46 insertions(+), 34 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 20b82443..71db0b08 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,8 +5,8 @@ "editor.smoothScrolling": true, "editor.tabSize": 2, "editor.codeActionsOnSave": { - "source.fixAll.eslint": true, - "source.fixAll": true + "source.fixAll.eslint": "explicit", + "source.fixAll": "explicit" }, "prisma-smart-formatter.typescript.defaultFormatter": "esbenp.prettier-vscode", "prisma-smart-formatter.prisma.defaultFormatter": "Prisma.prisma" diff --git a/src/whatsapp/controllers/chat.controller.ts b/src/whatsapp/controllers/chat.controller.ts index 0299841c..60a9c618 100644 --- a/src/whatsapp/controllers/chat.controller.ts +++ b/src/whatsapp/controllers/chat.controller.ts @@ -9,6 +9,7 @@ import { ProfilePictureDto, ProfileStatusDto, ReadMessageDto, + SendPresenceDto, WhatsAppNumberDto, } from '../dto/chat.dto'; import { InstanceDto } from '../dto/instance.dto'; @@ -77,6 +78,11 @@ export class ChatController { return await this.waMonitor.waInstances[instanceName].fetchChats(); } + public async sendPresence({ instanceName }: InstanceDto, data: SendPresenceDto) { + logger.verbose('requested sendPresence from ' + instanceName + ' instance'); + return await this.waMonitor.waInstances[instanceName].sendPresence(data); + } + public async fetchPrivacySettings({ instanceName }: InstanceDto) { logger.verbose('requested fetchPrivacySettings from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].fetchPrivacySettings(); diff --git a/src/whatsapp/controllers/sendMessage.controller.ts b/src/whatsapp/controllers/sendMessage.controller.ts index a6b844dc..20e38ae5 100644 --- a/src/whatsapp/controllers/sendMessage.controller.ts +++ b/src/whatsapp/controllers/sendMessage.controller.ts @@ -11,7 +11,6 @@ import { SendLocationDto, SendMediaDto, SendPollDto, - SendPresenceDto, SendReactionDto, SendStatusDto, SendStickerDto, @@ -24,11 +23,6 @@ const logger = new Logger('MessageRouter'); export class SendMessageController { constructor(private readonly waMonitor: WAMonitoringService) {} - public async sendPresence({ instanceName }: InstanceDto, data: SendPresenceDto) { - logger.verbose('requested sendPresence from ' + instanceName + ' instance'); - return await this.waMonitor.waInstances[instanceName].sendPresence(data); - } - public async sendText({ instanceName }: InstanceDto, data: SendTextDto) { logger.verbose('requested sendText from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].textMessage(data); diff --git a/src/whatsapp/dto/chat.dto.ts b/src/whatsapp/dto/chat.dto.ts index f8a5da5f..07553c90 100644 --- a/src/whatsapp/dto/chat.dto.ts +++ b/src/whatsapp/dto/chat.dto.ts @@ -1,4 +1,4 @@ -import { proto, WAPrivacyOnlineValue, WAPrivacyValue, WAReadReceiptsValue } from '@whiskeysockets/baileys'; +import { proto, WAPresence, WAPrivacyOnlineValue, WAPrivacyValue, WAReadReceiptsValue } from '@whiskeysockets/baileys'; export class OnWhatsAppDto { constructor(public readonly jid: string, public readonly exists: boolean, public readonly name?: string) {} @@ -83,3 +83,20 @@ export class DeleteMessage { remoteJid: string; participant?: string; } +export class Options { + delay?: number; + presence?: WAPresence; +} +class OptionsMessage { + options: Options; +} +export class Metadata extends OptionsMessage { + number: string; +} + +export class SendPresenceDto extends Metadata { + options: { + presence: WAPresence; + delay: number; + }; +} diff --git a/src/whatsapp/dto/sendMessage.dto.ts b/src/whatsapp/dto/sendMessage.dto.ts index 8cc4dd1e..bfa5763f 100644 --- a/src/whatsapp/dto/sendMessage.dto.ts +++ b/src/whatsapp/dto/sendMessage.dto.ts @@ -46,12 +46,7 @@ class PollMessage { values: string[]; messageSecret?: Uint8Array; } -export class SendPresenceDto extends Metadata { - options: { - presence: WAPresence; - delay: number; - }; -} + export class SendTextDto extends Metadata { textMessage: TextMessage; } diff --git a/src/whatsapp/routers/chat.router.ts b/src/whatsapp/routers/chat.router.ts index 285c29a0..29d1cdc3 100644 --- a/src/whatsapp/routers/chat.router.ts +++ b/src/whatsapp/routers/chat.router.ts @@ -7,6 +7,7 @@ import { deleteMessageSchema, messageUpSchema, messageValidateSchema, + presenceSchema, privacySettingsSchema, profileNameSchema, profilePictureSchema, @@ -26,6 +27,7 @@ import { ProfilePictureDto, ProfileStatusDto, ReadMessageDto, + SendPresenceDto, WhatsAppNumberDto, } from '../dto/chat.dto'; import { InstanceDto } from '../dto/instance.dto'; @@ -228,6 +230,22 @@ export class ChatRouter extends RouterBroker { return res.status(HttpStatus.OK).json(response); }) + .post(this.routerPath('sendPresence'), ...guards, async (req, res) => { + logger.verbose('request received in sendPresence'); + logger.verbose('request body: '); + logger.verbose(req.body); + + logger.verbose('request query: '); + logger.verbose(req.query); + const response = await this.dataValidate({ + request: req, + schema: presenceSchema, + ClassRef: SendPresenceDto, + execute: (instance, data) => chatController.sendPresence(instance, data), + }); + + return res.status(HttpStatus.CREATED).json(response); + }) // Profile routes .get(this.routerPath('fetchPrivacySettings'), ...guards, async (req, res) => { logger.verbose('request received in fetchPrivacySettings'); diff --git a/src/whatsapp/routers/sendMessage.router.ts b/src/whatsapp/routers/sendMessage.router.ts index 79fedbe2..d87db44d 100644 --- a/src/whatsapp/routers/sendMessage.router.ts +++ b/src/whatsapp/routers/sendMessage.router.ts @@ -9,7 +9,6 @@ import { locationMessageSchema, mediaMessageSchema, pollMessageSchema, - presenceSchema, reactionMessageSchema, statusMessageSchema, stickerMessageSchema, @@ -24,7 +23,6 @@ import { SendLocationDto, SendMediaDto, SendPollDto, - SendPresenceDto, SendReactionDto, SendStatusDto, SendStickerDto, @@ -39,22 +37,6 @@ export class MessageRouter extends RouterBroker { constructor(...guards: RequestHandler[]) { super(); this.router - .post(this.routerPath('sendPresence'), ...guards, async (req, res) => { - logger.verbose('request received in sendPresence'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ - request: req, - schema: presenceSchema, - ClassRef: SendPresenceDto, - execute: (instance, data) => sendMessageController.sendPresence(instance, data), - }); - - return res.status(HttpStatus.CREATED).json(response); - }) .post(this.routerPath('sendText'), ...guards, async (req, res) => { logger.verbose('request received in sendText'); logger.verbose('request body: '); diff --git a/src/whatsapp/services/whatsapp.service.ts b/src/whatsapp/services/whatsapp.service.ts index 83df4b74..a7b5152f 100644 --- a/src/whatsapp/services/whatsapp.service.ts +++ b/src/whatsapp/services/whatsapp.service.ts @@ -83,6 +83,7 @@ import { OnWhatsAppDto, PrivacySettingDto, ReadMessageDto, + SendPresenceDto, WhatsAppNumberDto, } from '../dto/chat.dto'; import { @@ -109,7 +110,6 @@ import { SendLocationDto, SendMediaDto, SendPollDto, - SendPresenceDto, SendReactionDto, SendStatusDto, SendStickerDto,