Skip to content
Merged
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
162 changes: 140 additions & 22 deletions src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ import {
import { chatwootImport } from '@api/integrations/chatbot/chatwoot/utils/chatwoot-import-helper';
import * as s3Service from '@api/integrations/storage/s3/libs/minio.server';
import { ProviderFiles } from '@api/provider/sessions';
import { PrismaRepository } from '@api/repository/repository.service';
import { PrismaRepository, Query } from '@api/repository/repository.service';
import { chatbotController, waMonitor } from '@api/server.module';
import { CacheService } from '@api/services/cache.service';
import { ChannelStartupService } from '@api/services/channel.service';
Expand All @@ -78,7 +78,7 @@ import { BadRequestException, InternalServerErrorException, NotFoundException }
import ffmpegPath from '@ffmpeg-installer/ffmpeg';
import { Boom } from '@hapi/boom';
import { createId as cuid } from '@paralleldrive/cuid2';
import { Instance } from '@prisma/client';
import { Instance, Message } from '@prisma/client';
import { createJid } from '@utils/createJid';
import { makeProxyAgent } from '@utils/makeProxyAgent';
import { getOnWhatsappCache, saveOnWhatsappCache } from '@utils/onWhatsappCache';
Expand Down Expand Up @@ -664,6 +664,10 @@ export class BaileysStartupService extends ChannelStartupService {
qrTimeout: 45_000,
emitOwnEvents: false,
shouldIgnoreJid: (jid) => {
if (this.localSettings.syncFullHistory && isJidGroup(jid)) {
return false;
}

const isGroupJid = this.localSettings.groupsIgnore && isJidGroup(jid);
const isBroadcast = !this.localSettings.readStatus && isJidBroadcast(jid);
const isNewsletter = isJidNewsletter(jid);
Expand Down Expand Up @@ -991,6 +995,17 @@ export class BaileysStartupService extends ChannelStartupService {
}
}

const contactsMap = new Map();

for (const contact of contacts) {
if (contact.id && (contact.notify || contact.name)) {
contactsMap.set(contact.id, {
name: contact.name ?? contact.notify,
jid: contact.id,
});
}
}

const chatsRaw: { remoteJid: string; instanceId: string; name?: string }[] = [];
const chatsRepository = new Set(
(
Expand Down Expand Up @@ -1062,6 +1077,15 @@ export class BaileysStartupService extends ChannelStartupService {
continue;
}

if (!m.pushName && !m.key.fromMe) {
const participantJid = m.participant || m.key.participant || m.key.remoteJid;
if (participantJid && contactsMap.has(participantJid)) {
m.pushName = contactsMap.get(participantJid).name;
} else if (participantJid) {
m.pushName = participantJid.split('@')[0];
}
}

messagesRaw.push(this.prepareMessage(m));
}

Expand Down Expand Up @@ -1173,25 +1197,6 @@ export class BaileysStartupService extends ChannelStartupService {
}
}

// if (received.messageStubParameters && received.messageStubParameters[0] === 'Message absent from node') {
// this.logger.info(`Recovering message lost messageId: ${received.key.id}`);

// await this.baileysCache.set(received.key.id, {
// message: received,
// retry: 0,
// });

// continue;
// }

// const retryCache = (await this.baileysCache.get(received.key.id)) || null;

// if (retryCache) {
// this.logger.info('Recovered message lost');
// await this.baileysCache.delete(received.key.id);
// }

// Cache to avoid duplicate messages
const messageKey = `${this.instance.id}_${received.key.id}`;
const cached = await this.baileysCache.get(messageKey);

Expand All @@ -1218,6 +1223,7 @@ export class BaileysStartupService extends ChannelStartupService {
if (settings?.groupsIgnore && received.key.remoteJid.includes('@g.us')) {
continue;
}

const existingChat = await this.prismaRepository.chat.findFirst({
where: { instanceId: this.instanceId, remoteJid: received.key.remoteJid },
select: { id: true, name: true },
Expand Down Expand Up @@ -4481,7 +4487,11 @@ export class BaileysStartupService extends ChannelStartupService {

const messageRaw = {
key: message.key,
pushName: message.pushName,
pushName:
message.pushName ||
(message.key.fromMe
? 'Você'
: message?.participant || (message.key?.participant ? message.key.participant.split('@')[0] : null)),
status: status[message.status],
message: { ...message.message },
contextInfo: contentMsg?.contextInfo,
Expand Down Expand Up @@ -4849,4 +4859,112 @@ export class BaileysStartupService extends ChannelStartupService {
throw new InternalServerErrorException('Error getCatalog', error.toString());
}
}

public async fetchMessages(query: Query<Message>) {
const keyFilters = query?.where?.key as {
id?: string;
fromMe?: boolean;
remoteJid?: string;
participants?: string;
};

const timestampFilter = {};
if (query?.where?.messageTimestamp) {
if (query.where.messageTimestamp['gte'] && query.where.messageTimestamp['lte']) {
timestampFilter['messageTimestamp'] = {
gte: Math.floor(new Date(query.where.messageTimestamp['gte']).getTime() / 1000),
lte: Math.floor(new Date(query.where.messageTimestamp['lte']).getTime() / 1000),
};
}
}

const count = await this.prismaRepository.message.count({
where: {
instanceId: this.instanceId,
id: query?.where?.id,
source: query?.where?.source,
messageType: query?.where?.messageType,
...timestampFilter,
AND: [
keyFilters?.id ? { key: { path: ['id'], equals: keyFilters?.id } } : {},
keyFilters?.fromMe ? { key: { path: ['fromMe'], equals: keyFilters?.fromMe } } : {},
keyFilters?.remoteJid ? { key: { path: ['remoteJid'], equals: keyFilters?.remoteJid } } : {},
keyFilters?.participants ? { key: { path: ['participants'], equals: keyFilters?.participants } } : {},
],
},
});

if (!query?.offset) {
query.offset = 50;
}

if (!query?.page) {
query.page = 1;
}

const messages = await this.prismaRepository.message.findMany({
where: {
instanceId: this.instanceId,
id: query?.where?.id,
source: query?.where?.source,
messageType: query?.where?.messageType,
...timestampFilter,
AND: [
keyFilters?.id ? { key: { path: ['id'], equals: keyFilters?.id } } : {},
keyFilters?.fromMe ? { key: { path: ['fromMe'], equals: keyFilters?.fromMe } } : {},
keyFilters?.remoteJid ? { key: { path: ['remoteJid'], equals: keyFilters?.remoteJid } } : {},
keyFilters?.participants ? { key: { path: ['participants'], equals: keyFilters?.participants } } : {},
],
},
orderBy: {
messageTimestamp: 'desc',
},
skip: query.offset * (query?.page === 1 ? 0 : (query?.page as number) - 1),
take: query.offset,
select: {
id: true,
key: true,
pushName: true,
messageType: true,
message: true,
messageTimestamp: true,
instanceId: true,
source: true,
contextInfo: true,
MessageUpdate: {
select: {
status: true,
},
},
},
});

const formattedMessages = messages.map((message) => {
const messageKey = message.key as { fromMe: boolean; remoteJid: string; id: string; participant?: string };

if (!message.pushName) {
if (messageKey.fromMe) {
message.pushName = 'Você';
} else if (message.contextInfo) {
const contextInfo = message.contextInfo as { participant?: string };
if (contextInfo.participant) {
message.pushName = contextInfo.participant.split('@')[0];
} else if (messageKey.participant) {
message.pushName = messageKey.participant.split('@')[0];
}
}
}

return message;
});

return {
messages: {
total: count,
pages: Math.ceil(count / query.offset),
currentPage: query.page,
records: formattedMessages,
},
};
}
}