Skip to content

Update whatsapp.business.service.ts #1403

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 132 additions & 51 deletions src/api/integrations/channel/meta/whatsapp.business.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,34 +191,64 @@
return content;
}

private messageTextJson(received: any) {
let content: any;
const message = received.messages[0];
if (message.from === received.metadata.phone_number_id) {
content = {
extendedTextMessage: { text: message.text.body },
};
message.context ? (content = { ...content, contextInfo: { stanzaId: message.context.id } }) : content;
private messageTextJson(received: any) {

Check failure on line 194 in src/api/integrations/channel/meta/whatsapp.business.service.ts

View workflow job for this annotation

GitHub Actions / check-lint-and-build

Insert `··`
// Verificar que received y received.messages existen

Check failure on line 195 in src/api/integrations/channel/meta/whatsapp.business.service.ts

View workflow job for this annotation

GitHub Actions / check-lint-and-build

Insert `··`
if (!received || !received.messages || received.messages.length === 0) {

Check failure on line 196 in src/api/integrations/channel/meta/whatsapp.business.service.ts

View workflow job for this annotation

GitHub Actions / check-lint-and-build

Replace `··` with `····`
this.logger.error('Error: received object or messages array is undefined or empty');

Check failure on line 197 in src/api/integrations/channel/meta/whatsapp.business.service.ts

View workflow job for this annotation

GitHub Actions / check-lint-and-build

Insert `··`
return null;

Check failure on line 198 in src/api/integrations/channel/meta/whatsapp.business.service.ts

View workflow job for this annotation

GitHub Actions / check-lint-and-build

Insert `··`
}

Check failure on line 199 in src/api/integrations/channel/meta/whatsapp.business.service.ts

View workflow job for this annotation

GitHub Actions / check-lint-and-build

Insert `··`

Check failure on line 200 in src/api/integrations/channel/meta/whatsapp.business.service.ts

View workflow job for this annotation

GitHub Actions / check-lint-and-build

Replace `··⏎` with `⏎··`
const message = received.messages[0];
let content: any;

Check failure on line 202 in src/api/integrations/channel/meta/whatsapp.business.service.ts

View workflow job for this annotation

GitHub Actions / check-lint-and-build

Insert `··`

Check failure on line 203 in src/api/integrations/channel/meta/whatsapp.business.service.ts

View workflow job for this annotation

GitHub Actions / check-lint-and-build

Replace `··⏎` with `⏎··`
// Verificar si es un mensaje de tipo sticker, location u otro tipo que no tiene text
if (!message.text) {

Check failure on line 205 in src/api/integrations/channel/meta/whatsapp.business.service.ts

View workflow job for this annotation

GitHub Actions / check-lint-and-build

Insert `··`
// Si no hay texto, manejamos diferente según el tipo de mensaje
if (message.type === 'sticker') {
content = { stickerMessage: {} };
} else if (message.type === 'location') {
content = { locationMessage: {
degreesLatitude: message.location?.latitude,
degreesLongitude: message.location?.longitude,
name: message.location?.name,
address: message.location?.address,
}};
} else {
content = { conversation: message.text.body };
message.context ? (content = { ...content, contextInfo: { stanzaId: message.context.id } }) : content;
// Para otros tipos de mensajes sin texto, creamos un contenido genérico
this.logger.log(`Mensaje de tipo ${message.type} sin campo text`);
content = { [message.type + 'Message']: message[message.type] || {} };
}

// Añadir contexto si existe
if (message.context) {
content = { ...content, contextInfo: { stanzaId: message.context.id } };
}

return content;
}

// Si el mensaje tiene texto, procesamos normalmente
if (!received.metadata || !received.metadata.phone_number_id) {
this.logger.error('Error: metadata or phone_number_id is undefined');
return null;
}

private messageLocationJson(received: any) {
const message = received.messages[0];
let content: any = {
locationMessage: {
degreesLatitude: message.location.latitude,
degreesLongitude: message.location.longitude,
name: message.location?.name,
address: message.location?.address,
},
if (message.from === received.metadata.phone_number_id) {
content = {
extendedTextMessage: { text: message.text.body },
};
message.context ? (content = { ...content, contextInfo: { stanzaId: message.context.id } }) : content;
return content;
if (message.context) {
content = { ...content, contextInfo: { stanzaId: message.context.id } };
}
} else {
content = { conversation: message.text.body };
if (message.context) {
content = { ...content, contextInfo: { stanzaId: message.context.id } };
}
}

return content;
}

private messageContactsJson(received: any) {
const message = received.messages[0];
Expand Down Expand Up @@ -277,7 +307,7 @@

private renderMessageType(type: string) {
let messageType: string;

switch (type) {
case 'text':
messageType = 'conversation';
Expand All @@ -300,28 +330,48 @@
case 'location':
messageType = 'locationMessage';
break;
case 'sticker':
messageType = 'stickerMessage';
break;
default:
messageType = 'conversation';
break;
}

return messageType;
}

protected async messageHandle(received: any, database: Database, settings: any) {
try {
let messageRaw: any;
let pushName: any;

if (received.contacts) pushName = received.contacts[0].profile.name;

if (received.messages) {
const message = received.messages[0]; // Añadir esta línea para definir message

const key = {
id: received.messages[0].id,
id: message.id,
remoteJid: this.phoneNumber,
fromMe: received.messages[0].from === received.metadata.phone_number_id,
fromMe: message.from === received.metadata.phone_number_id,
};
if (this.isMediaMessage(received?.messages[0])) {

if (message.type === 'sticker') {
this.logger.log('Procesando mensaje de tipo sticker');
messageRaw = {
key,
pushName,
message: {
stickerMessage: message.sticker || {},
},
messageType: 'stickerMessage',
messageTimestamp: parseInt(message.timestamp) as number,
source: 'unknown',
instanceId: this.instanceId,
};
} else if (this.isMediaMessage(message)) {

messageRaw = {
key,
pushName,
Expand Down Expand Up @@ -455,17 +505,6 @@
source: 'unknown',
instanceId: this.instanceId,
};
} else if (received?.messages[0].location) {
messageRaw = {
key,
pushName,
message: this.messageLocationJson(received),
contextInfo: this.messageLocationJson(received)?.contextInfo,
messageType: this.renderMessageType(received.messages[0].type),
messageTimestamp: parseInt(received.messages[0].timestamp) as number,
source: 'unknown',
instanceId: this.instanceId,
};
} else {
messageRaw = {
key,
Expand Down Expand Up @@ -539,7 +578,7 @@
}
}

if (!this.isMediaMessage(received?.messages[0])) {
if (!this.isMediaMessage(message) && message.type !== 'sticker') {
await this.prismaRepository.message.create({
data: messageRaw,
});
Expand Down Expand Up @@ -742,10 +781,47 @@
}

protected async eventHandler(content: any) {
const database = this.configService.get<Database>('DATABASE');
const settings = await this.findSettings();

this.messageHandle(content, database, settings);
try {
// Registro para depuración
this.logger.log('Contenido recibido en eventHandler:');
this.logger.log(JSON.stringify(content, null, 2));
Comment on lines +786 to +787
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 question (security): Beware of verbose logging.

Logging the entire content in JSON might expose sensitive information. Ensure such detailed logging is controlled by environment or a log level setting when in production.


const database = this.configService.get<Database>('DATABASE');
const settings = await this.findSettings();

// Si hay mensajes, verificar primero el tipo
if (content.messages && content.messages.length > 0) {
const message = content.messages[0];
this.logger.log(`Tipo de mensaje recibido: ${message.type}`);

// Verificamos el tipo de mensaje antes de procesarlo
if (message.type === 'text' ||
message.type === 'image' ||
message.type === 'video' ||
message.type === 'audio' ||
message.type === 'document' ||
message.type === 'sticker' ||
message.type === 'location' ||
message.type === 'contacts' ||
message.type === 'interactive' ||
message.type === 'button' ||
message.type === 'reaction') {

// Procesar el mensaje normalmente
this.messageHandle(content, database, settings);
} else {
this.logger.warn(`Tipo de mensaje no reconocido: ${message.type}`);
}
} else if (content.statuses) {
// Procesar actualizaciones de estado
this.messageHandle(content, database, settings);
} else {
this.logger.warn('No se encontraron mensajes ni estados en el contenido recibido');
}
} catch (error) {
this.logger.error('Error en eventHandler:');
this.logger.error(error);
}
}

protected async sendMessageWithTyping(number: string, message: any, options?: Options, isIntegration = false) {
Expand Down Expand Up @@ -828,7 +904,6 @@
}
if (message['media']) {
const isImage = message['mimetype']?.startsWith('image/');
const isVideo = message['mimetype']?.startsWith('video/');

content = {
messaging_product: 'whatsapp',
Expand All @@ -838,7 +913,7 @@
[message['mediaType']]: {
[message['type']]: message['id'],
preview_url: linkPreview,
...(message['fileName'] && !isImage && !isVideo && { filename: message['fileName'] }),
...(message['fileName'] && !isImage && { filename: message['fileName'] }),
caption: message['caption'],
},
};
Expand Down Expand Up @@ -1006,10 +1081,8 @@

private async getIdMedia(mediaMessage: any) {
const formData = new FormData();
const media = mediaMessage.media || mediaMessage.audio;
if (!media) throw new Error('Media or audio not found');

const fileStream = createReadStream(media);
const fileStream = createReadStream(mediaMessage.media);

formData.append('file', fileStream, { filename: 'media', contentType: mediaMessage.mimetype });
formData.append('typeFile', mediaMessage.mimetype);
Expand Down Expand Up @@ -1110,7 +1183,7 @@
const prepareMedia: any = {
fileName: `${hash}.mp3`,
mediaType: 'audio',
audio,
media: audio,
};

if (isURL(audio)) {
Expand All @@ -1132,7 +1205,15 @@
public async audioWhatsapp(data: SendAudioDto, file?: any, isIntegration = false) {
const mediaData: SendAudioDto = { ...data };

if (file) mediaData.audio = file.buffer.toString('base64');
if (file?.buffer) {
mediaData.audio = file.buffer.toString('base64');
} else if (isURL(mediaData.audio)) {
// DO NOTHING
// mediaData.audio = mediaData.audio;
} else {
console.error('El archivo no tiene buffer o file es undefined');
throw new Error('File or buffer is undefined');
}

const message = await this.processAudio(mediaData.audio, data.number);

Expand Down