mirror of
https://github.com/EvolutionAPI/evolution-api.git
synced 2026-01-15 08:12:24 -06:00
fix: Trata eventos de edição/deleção, caption, undefined e implementa deduplicação e refactoring do LID
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -53,7 +53,7 @@ export class ChatwootService {
|
|||||||
private readonly configService: ConfigService,
|
private readonly configService: ConfigService,
|
||||||
private readonly prismaRepository: PrismaRepository,
|
private readonly prismaRepository: PrismaRepository,
|
||||||
private readonly cache: CacheService,
|
private readonly cache: CacheService,
|
||||||
) {}
|
) { }
|
||||||
|
|
||||||
private pgClient = postgresClient.getChatwootConnection();
|
private pgClient = postgresClient.getChatwootConnection();
|
||||||
|
|
||||||
@@ -2024,7 +2024,7 @@ export class ChatwootService {
|
|||||||
const fileData = Buffer.from(downloadBase64.base64, 'base64');
|
const fileData = Buffer.from(downloadBase64.base64, 'base64');
|
||||||
|
|
||||||
const fileStream = new Readable();
|
const fileStream = new Readable();
|
||||||
fileStream._read = () => {};
|
fileStream._read = () => { };
|
||||||
fileStream.push(fileData);
|
fileStream.push(fileData);
|
||||||
fileStream.push(null);
|
fileStream.push(null);
|
||||||
|
|
||||||
@@ -2142,7 +2142,7 @@ export class ChatwootService {
|
|||||||
const processedBuffer = await img.getBuffer(JimpMime.png);
|
const processedBuffer = await img.getBuffer(JimpMime.png);
|
||||||
|
|
||||||
const fileStream = new Readable();
|
const fileStream = new Readable();
|
||||||
fileStream._read = () => {}; // _read is required but you can noop it
|
fileStream._read = () => { }; // _read is required but you can noop it
|
||||||
fileStream.push(processedBuffer);
|
fileStream.push(processedBuffer);
|
||||||
fileStream.push(null);
|
fileStream.push(null);
|
||||||
|
|
||||||
@@ -2237,56 +2237,103 @@ export class ChatwootService {
|
|||||||
return send;
|
return send;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// DELETE
|
||||||
|
// Hard delete quando habilitado; senão cria placeholder "apagada pelo remetente"
|
||||||
if (event === Events.MESSAGES_DELETE) {
|
if (event === Events.MESSAGES_DELETE) {
|
||||||
|
// Anti-dup local (process-wide) por 15s
|
||||||
|
const dedupKey = `cw_del_${instance.instanceId}_${body?.key?.id}`;
|
||||||
|
const g = (global as any);
|
||||||
|
if (!g.__cwDel) g.__cwDel = new Map<string, number>();
|
||||||
|
const last = g.__cwDel.get(dedupKey);
|
||||||
|
const now = Date.now();
|
||||||
|
if (last && now - last < 15000) {
|
||||||
|
this.logger.info(`[CW.DELETE] Ignorado (duplicado local) para ${body?.key?.id}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
g.__cwDel.set(dedupKey, now);
|
||||||
|
|
||||||
const chatwootDelete = this.configService.get<Chatwoot>('CHATWOOT').MESSAGE_DELETE;
|
const chatwootDelete = this.configService.get<Chatwoot>('CHATWOOT').MESSAGE_DELETE;
|
||||||
|
|
||||||
if (chatwootDelete === true) {
|
|
||||||
if (!body?.key?.id) {
|
if (!body?.key?.id) {
|
||||||
this.logger.warn('message id not found');
|
this.logger.warn('message id not found');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const message = await this.getMessageByKeyId(instance, body.key.id);
|
const message = await this.getMessageByKeyId(instance, body.key.id);
|
||||||
|
if (!message) {
|
||||||
|
this.logger.warn('Message not found for delete event');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (message?.chatwootMessageId && message?.chatwootConversationId) {
|
if (chatwootDelete === true && message?.chatwootMessageId && message?.chatwootConversationId) {
|
||||||
await this.prismaRepository.message.deleteMany({
|
await this.prismaRepository.message.deleteMany({
|
||||||
where: {
|
where: {
|
||||||
key: {
|
key: { path: ['id'], equals: body.key.id },
|
||||||
path: ['id'],
|
|
||||||
equals: body.key.id,
|
|
||||||
},
|
|
||||||
instanceId: instance.instanceId,
|
instanceId: instance.instanceId,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return await client.messages.delete({
|
await client.messages.delete({
|
||||||
accountId: this.provider.accountId,
|
accountId: this.provider.accountId,
|
||||||
conversationId: message.chatwootConversationId,
|
conversationId: message.chatwootConversationId,
|
||||||
messageId: message.chatwootMessageId,
|
messageId: message.chatwootMessageId,
|
||||||
});
|
});
|
||||||
|
return; // hard delete
|
||||||
|
} else {
|
||||||
|
const key = message.key as WAMessageKey;
|
||||||
|
const messageType = key?.fromMe ? 'outgoing' : 'incoming';
|
||||||
|
const DELETE_PLACEHOLDER = '🗑️ Mensagem apagada pelo remetente';
|
||||||
|
|
||||||
|
if (message.chatwootConversationId) {
|
||||||
|
const send = await this.createMessage(
|
||||||
|
instance,
|
||||||
|
message.chatwootConversationId,
|
||||||
|
DELETE_PLACEHOLDER,
|
||||||
|
messageType,
|
||||||
|
false,
|
||||||
|
[],
|
||||||
|
{ message: { extendedTextMessage: { contextInfo: { stanzaId: key.id } } } },
|
||||||
|
'DEL:' + body.key.id, // mantém a intenção de idempotência
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
if (!send) this.logger.warn('delete placeholder not sent');
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EDIT
|
||||||
|
// Cria "Mensagem editada: <texto>" SOMENTE se houver texto (evita 'undefined')
|
||||||
|
// Se vier "edit" sem texto (REVOKE mascarado), não faz nada aqui — o bloco de DELETE trata.
|
||||||
if (event === 'messages.edit' || event === 'send.message.update') {
|
if (event === 'messages.edit' || event === 'send.message.update') {
|
||||||
const editedMessageContent =
|
const editedMessageContentRaw =
|
||||||
body?.editedMessage?.conversation || body?.editedMessage?.extendedTextMessage?.text;
|
body?.editedMessage?.conversation ??
|
||||||
const message = await this.getMessageByKeyId(instance, body?.key?.id);
|
body?.editedMessage?.extendedTextMessage?.text ??
|
||||||
|
body?.editedMessage?.imageMessage?.caption ??
|
||||||
|
body?.editedMessage?.videoMessage?.caption ??
|
||||||
|
body?.editedMessage?.documentMessage?.caption ??
|
||||||
|
(typeof body?.text === 'string' ? body.text : undefined);
|
||||||
|
|
||||||
|
const editedMessageContent = (editedMessageContentRaw ?? '').trim();
|
||||||
|
|
||||||
|
// Sem conteúdo? Ignora aqui. O DELETE vai gerar o placeholder se for o caso.
|
||||||
|
if (!editedMessageContent) {
|
||||||
|
this.logger.info('[CW.EDIT] Conteúdo vazio — ignorando (DELETE tratará se for revoke).');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const message = await this.getMessageByKeyId(instance, body?.key?.id);
|
||||||
if (!message) {
|
if (!message) {
|
||||||
this.logger.warn('Message not found for edit event');
|
this.logger.warn('Message not found for edit event');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const key = message.key as WAMessageKey;
|
const key = message.key as WAMessageKey;
|
||||||
|
|
||||||
const messageType = key?.fromMe ? 'outgoing' : 'incoming';
|
const messageType = key?.fromMe ? 'outgoing' : 'incoming';
|
||||||
|
|
||||||
if (message && message.chatwootConversationId && message.chatwootMessageId) {
|
if (message.chatwootConversationId) {
|
||||||
// Criar nova mensagem com formato: "Mensagem editada:\n\nteste1"
|
const label = `\`${i18next.t('cw.message.edited')}\``; // "Mensagem editada"
|
||||||
const editedText = `\n\n\`${i18next.t('cw.message.edited')}:\`\n\n${editedMessageContent}`;
|
const editedText = `${label}:${editedMessageContent}`;
|
||||||
|
|
||||||
const send = await this.createMessage(
|
const send = await this.createMessage(
|
||||||
instance,
|
instance,
|
||||||
message.chatwootConversationId,
|
message.chatwootConversationId,
|
||||||
@@ -2294,20 +2341,17 @@ export class ChatwootService {
|
|||||||
messageType,
|
messageType,
|
||||||
false,
|
false,
|
||||||
[],
|
[],
|
||||||
{
|
{ message: { extendedTextMessage: { contextInfo: { stanzaId: key.id } } } },
|
||||||
message: { extendedTextMessage: { contextInfo: { stanzaId: key.id } } },
|
|
||||||
},
|
|
||||||
'WAID:' + body.key.id,
|
'WAID:' + body.key.id,
|
||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
if (!send) {
|
if (!send) this.logger.warn('edited message not sent');
|
||||||
this.logger.warn('edited message not sent');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIM DA EDIÇÃO
|
||||||
|
|
||||||
if (event === 'messages.read') {
|
if (event === 'messages.read') {
|
||||||
if (!body?.key?.id || !body?.key?.remoteJid) {
|
if (!body?.key?.id || !body?.key?.remoteJid) {
|
||||||
this.logger.warn('message id not found');
|
this.logger.warn('message id not found');
|
||||||
@@ -2399,7 +2443,7 @@ export class ChatwootService {
|
|||||||
const fileData = Buffer.from(body?.qrcode.base64.replace('data:image/png;base64,', ''), 'base64');
|
const fileData = Buffer.from(body?.qrcode.base64.replace('data:image/png;base64,', ''), 'base64');
|
||||||
|
|
||||||
const fileStream = new Readable();
|
const fileStream = new Readable();
|
||||||
fileStream._read = () => {};
|
fileStream._read = () => { };
|
||||||
fileStream.push(fileData);
|
fileStream.push(fileData);
|
||||||
fileStream.push(null);
|
fileStream.push(null);
|
||||||
|
|
||||||
|
|||||||
@@ -117,24 +117,21 @@ export async function saveOnWhatsappCache(data: ISaveOnWhatsappCacheParams[]) {
|
|||||||
`Saving: remoteJid=${remoteJid}, jidOptions=${uniqueNumbers.join(',')}, lid=${item.lid === 'lid' || item.remoteJid?.includes('@lid') ? 'lid' : null}`,
|
`Saving: remoteJid=${remoteJid}, jidOptions=${uniqueNumbers.join(',')}, lid=${item.lid === 'lid' || item.remoteJid?.includes('@lid') ? 'lid' : null}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (existingRecord) {
|
await prismaRepository.isOnWhatsapp.upsert({
|
||||||
await prismaRepository.isOnWhatsapp.update({
|
where: { remoteJid: remoteJid }, // Prisma tenta encontrar o registro aqui
|
||||||
where: { id: existingRecord.id },
|
|
||||||
data: {
|
update: {
|
||||||
|
// Campos de update
|
||||||
|
jidOptions: uniqueNumbers.join(','),
|
||||||
|
lid: item.lid === 'lid' || item.remoteJid?.includes('@lid') ? 'lid' : null,
|
||||||
|
}, // Se encontrar, ele atualiza
|
||||||
|
create: {
|
||||||
|
// Campos de criação
|
||||||
remoteJid: remoteJid,
|
remoteJid: remoteJid,
|
||||||
jidOptions: uniqueNumbers.join(','),
|
jidOptions: uniqueNumbers.join(','),
|
||||||
lid: item.lid === 'lid' || item.remoteJid?.includes('@lid') ? 'lid' : null,
|
lid: item.lid === 'lid' || item.remoteJid?.includes('@lid') ? 'lid' : null,
|
||||||
},
|
}, // Se NÃO encontrar, ele cria
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
await prismaRepository.isOnWhatsapp.create({
|
|
||||||
data: {
|
|
||||||
remoteJid: remoteJid,
|
|
||||||
jidOptions: uniqueNumbers.join(','),
|
|
||||||
lid: item.lid === 'lid' || item.remoteJid?.includes('@lid') ? 'lid' : null,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user