From f6d4f940a3c40ae94b97e1d1df1a196b400ba0d2 Mon Sep 17 00:00:00 2001 From: Davidson Gomes Date: Fri, 12 Jul 2024 09:40:15 -0300 Subject: [PATCH] chore: Update cloud API message sending for lists and buttons This commit updates the way messages are sent to the cloud API for lists and buttons, adjusting the structure of the request payload. The affected files include: - sendMessage.dto.ts: updates the format of the Button class - sendMessage.router.ts: adds a new route for sending button messages - whatsapp.business.service.ts: updates the handling of list and button messages - message.schema.ts: adds a new schema for button messages These changes improve the integration with the cloud API and allow for better handling of lists and buttons in messages. --- src/api/dto/sendMessage.dto.ts | 9 +-- src/api/routes/sendMessage.router.ts | 22 ++++---- .../channels/whatsapp.business.service.ts | 56 +++++++++---------- src/validate/message.schema.ts | 45 +++++++++++++++ 4 files changed, 88 insertions(+), 44 deletions(-) diff --git a/src/api/dto/sendMessage.dto.ts b/src/api/dto/sendMessage.dto.ts index 46839366..07ef804e 100644 --- a/src/api/dto/sendMessage.dto.ts +++ b/src/api/dto/sendMessage.dto.ts @@ -90,18 +90,15 @@ export class SendAudioDto extends Metadata { } class Button { - buttonText: string; - buttonId: string; + text: string; + id: string; } -class ButtonMessage { +export class SendButtonDto extends Metadata { title: string; description: string; footerText?: string; buttons: Button[]; } -export class SendButtonDto extends Metadata { - buttonMessage: ButtonMessage; -} export class SendLocationDto extends Metadata { latitude: number; diff --git a/src/api/routes/sendMessage.router.ts b/src/api/routes/sendMessage.router.ts index 006b49ef..b8bee8e5 100644 --- a/src/api/routes/sendMessage.router.ts +++ b/src/api/routes/sendMessage.router.ts @@ -2,6 +2,7 @@ import { RequestHandler, Router } from 'express'; import { audioMessageSchema, + buttonMessageSchema, contactMessageSchema, listMessageSchema, locationMessageSchema, @@ -16,6 +17,7 @@ import { import { RouterBroker } from '../abstract/abstract.router'; import { SendAudioDto, + SendButtonDto, SendContactDto, SendListDto, SendLocationDto, @@ -144,17 +146,17 @@ export class MessageRouter extends RouterBroker { }); return res.status(HttpStatus.CREATED).json(response); - }); - // .post(this.routerPath('sendButtons'), ...guards, async (req, res) => { - // const response = await this.dataValidate({ - // request: req, - // schema: buttonMessageSchema, - // ClassRef: SendButtonDto, - // execute: (instance, data) => sendMessageController.sendButtons(instance, data), - // }); + }) + .post(this.routerPath('sendButtons'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: buttonMessageSchema, + ClassRef: SendButtonDto, + execute: (instance, data) => sendMessageController.sendButtons(instance, data), + }); - // return res.status(HttpStatus.CREATED).json(response); - // }) + return res.status(HttpStatus.CREATED).json(response); + }); } public readonly router = Router(); diff --git a/src/api/services/channels/whatsapp.business.service.ts b/src/api/services/channels/whatsapp.business.service.ts index 4f51c9b6..d5fd9289 100644 --- a/src/api/services/channels/whatsapp.business.service.ts +++ b/src/api/services/channels/whatsapp.business.service.ts @@ -738,7 +738,7 @@ export class BusinessStartupService extends ChannelStartupService { message = { conversation: `${message['text'] || 'Select'}\n` + formattedText }; return await this.post(content, 'messages'); } - if (message['sections']) { + if (message['listMessage']) { content = { messaging_product: 'whatsapp', recipient_type: 'individual', @@ -748,29 +748,29 @@ export class BusinessStartupService extends ChannelStartupService { type: 'list', header: { type: 'text', - text: message['title'], + text: message['listMessage']['title'], }, body: { - text: message['text'], + text: message['listMessage']['description'], }, footer: { - text: message['footerText'], + text: message['listMessage']['footerText'], }, action: { - button: message['buttonText'], - sections: message['sections'], + button: message['listMessage']['buttonText'], + sections: message['listMessage']['sections'], }, }, }; quoted ? (content.context = { message_id: quoted.id }) : content; let formattedText = ''; - for (const section of message['sections']) { + for (const section of message['listMessage']['sections']) { formattedText += `${section?.title}\n`; for (const row of section.rows) { formattedText += `${row?.title}\n`; } } - message = { conversation: `${message['title']}\n` + formattedText }; + message = { conversation: `${message['listMessage']['title']}\n` + formattedText }; return await this.post(content, 'messages'); } if (message['template']) { @@ -993,8 +993,8 @@ export class BusinessStartupService extends ChannelStartupService { const embeddedMedia: any = {}; const btnItems = { - text: data.buttonMessage.buttons.map((btn) => btn.buttonText), - ids: data.buttonMessage.buttons.map((btn) => btn.buttonId), + text: data.buttons.map((btn) => btn.text), + ids: data.buttons.map((btn) => btn.id), }; if (!arrayUnique(btnItems.text) || !arrayUnique(btnItems.ids)) { @@ -1004,13 +1004,13 @@ export class BusinessStartupService extends ChannelStartupService { return await this.sendMessageWithTyping( data.number, { - text: !embeddedMedia?.mediaKey ? data.buttonMessage.title : undefined, - buttons: data.buttonMessage.buttons.map((button) => { + text: !embeddedMedia?.mediaKey ? data.title : undefined, + buttons: data.buttons.map((button) => { return { type: 'reply', reply: { - title: button.buttonText, - id: button.buttonId, + title: button.text, + id: button.id, }, }; }), @@ -1058,11 +1058,10 @@ export class BusinessStartupService extends ChannelStartupService { throw new BadRequestException('Section tiles cannot be repeated'); } - return await this.sendMessageWithTyping( - data.number, - { + const sendData: any = { + listMessage: { title: data.title, - text: data.description, + description: data.description, footerText: data?.footerText, buttonText: data?.buttonText, sections: data.sections.map((section) => { @@ -1071,22 +1070,23 @@ export class BusinessStartupService extends ChannelStartupService { rows: section.rows.map((row) => { return { title: row.title, - description: row.description, + description: row.description.substring(0, 72), id: row.rowId, }; }), }; }), }, - { - delay: data?.delay, - presence: 'composing', - quoted: data?.quoted, - linkPreview: data?.linkPreview, - mentionsEveryOne: data?.mentionsEveryOne, - mentioned: data?.mentioned, - }, - ); + }; + + return await this.sendMessageWithTyping(data.number, sendData, { + delay: data?.delay, + presence: 'composing', + quoted: data?.quoted, + linkPreview: data?.linkPreview, + mentionsEveryOne: data?.mentionsEveryOne, + mentioned: data?.mentioned, + }); } public async templateMessage(data: SendTemplateDto, isIntegration = false) { diff --git a/src/validate/message.schema.ts b/src/validate/message.schema.ts index 1f7548b1..fee7bcfe 100644 --- a/src/validate/message.schema.ts +++ b/src/validate/message.schema.ts @@ -358,3 +358,48 @@ export const listMessageSchema: JSONSchema7 = { }, required: ['number', 'title', 'footerText', 'buttonText', 'sections'], }; + +export const buttonMessageSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + number: { ...numberDefinition }, + title: { type: 'string' }, + description: { type: 'string' }, + footerText: { type: 'string' }, + buttons: { + type: 'array', + minItems: 1, + uniqueItems: true, + items: { + type: 'object', + properties: { + text: { type: 'string' }, + id: { type: 'string' }, + }, + required: ['text', 'id'], + ...isNotEmpty('text', 'id'), + }, + }, + media: { type: 'string' }, + fileName: { type: 'string' }, + mediatype: { type: 'string', enum: ['image', 'document', 'video'] }, + delay: { + type: 'integer', + description: 'Enter a value in milliseconds', + }, + quoted: { ...quotedOptionsSchema }, + everyOne: { type: 'boolean', enum: [true, false] }, + mentioned: { + type: 'array', + minItems: 1, + uniqueItems: true, + items: { + type: 'string', + pattern: '^\\d+', + description: '"mentioned" must be an array of numeric strings', + }, + }, + }, + required: ['number', 'title', 'buttons'], +};