feat(IsOnWhatsapp): add optional lid field and update related logic

- Introduced a new optional `lid` field in the IsOnWhatsapp model to enhance data tracking.
- Updated migration script to add the `lid` column to the database.
- Modified OnWhatsAppDto to include the `lid` property for better integration with WhatsApp user data.
- Enhanced the WhatsApp Baileys service to handle `lid` numbers separately and improve user verification logic.
- Updated cache handling functions to support the new `lid` field for consistent data management.
This commit is contained in:
Davidson Gomes 2025-06-13 11:52:32 -03:00
parent c17b48bca0
commit afc2927837
6 changed files with 138 additions and 76 deletions

View File

@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "IsOnWhatsapp" ADD COLUMN "lid" VARCHAR(100);

View File

@ -648,6 +648,7 @@ model IsOnWhatsapp {
id String @id @default(cuid()) id String @id @default(cuid())
remoteJid String @unique @db.VarChar(100) remoteJid String @unique @db.VarChar(100)
jidOptions String jidOptions String
lid String? @db.VarChar(100)
createdAt DateTime @default(now()) @db.Timestamp createdAt DateTime @default(now()) @db.Timestamp
updatedAt DateTime @updatedAt @db.Timestamp updatedAt DateTime @updatedAt @db.Timestamp
} }

View File

@ -13,6 +13,7 @@ export class OnWhatsAppDto {
public readonly exists: boolean, public readonly exists: boolean,
public readonly number: string, public readonly number: string,
public readonly name?: string, public readonly name?: string,
public readonly lid?: string,
) {} ) {}
} }

View File

@ -1170,7 +1170,7 @@ export class BaileysStartupService extends ChannelStartupService {
) { ) {
const chatwootSentMessage = await this.chatwootService.eventWhatsapp( const chatwootSentMessage = await this.chatwootService.eventWhatsapp(
Events.MESSAGES_UPSERT, Events.MESSAGES_UPSERT,
{ instanceName: this.instance.name, instanceId: this.instance.id }, { instanceName: this.instance.name, instanceId: this.instanceId },
messageRaw, messageRaw,
); );
@ -3131,10 +3131,10 @@ export class BaileysStartupService extends ChannelStartupService {
const group = await this.findGroup({ groupJid: jid }, 'inner'); const group = await this.findGroup({ groupJid: jid }, 'inner');
if (!group) { if (!group) {
new OnWhatsAppDto(jid, false, number); return new OnWhatsAppDto(jid, false, number);
} }
return new OnWhatsAppDto(group.id, !!group?.id, number, group?.subject); return new OnWhatsAppDto(group.id, true, number, group?.subject);
}), }),
); );
onWhatsapp.push(...groups); onWhatsapp.push(...groups);
@ -3144,26 +3144,40 @@ export class BaileysStartupService extends ChannelStartupService {
where: { instanceId: this.instanceId, remoteJid: { in: jids.users.map(({ jid }) => jid) } }, where: { instanceId: this.instanceId, remoteJid: { in: jids.users.map(({ jid }) => jid) } },
}); });
const numbersToVerify = jids.users.map(({ jid }) => jid.replace('+', '')); // Separate @lid numbers from normal numbers
const lidUsers = jids.users.filter(({ jid }) => jid.includes('@lid'));
const normalUsers = jids.users.filter(({ jid }) => !jid.includes('@lid'));
// For normal numbers, use traditional Baileys verification
let normalVerifiedUsers: OnWhatsAppDto[] = [];
if (normalUsers.length > 0) {
console.log('normalUsers', normalUsers);
const numbersToVerify = normalUsers.map(({ jid }) => jid.replace('+', ''));
console.log('numbersToVerify', numbersToVerify);
const cachedNumbers = await getOnWhatsappCache(numbersToVerify); const cachedNumbers = await getOnWhatsappCache(numbersToVerify);
console.log('cachedNumbers', cachedNumbers);
const filteredNumbers = numbersToVerify.filter( const filteredNumbers = numbersToVerify.filter(
(jid) => !cachedNumbers.some((cached) => cached.jidOptions.includes(jid)), (jid) => !cachedNumbers.some((cached) => cached.jidOptions.includes(jid)),
); );
console.log('filteredNumbers', filteredNumbers);
const verify = await this.client.onWhatsApp(...filteredNumbers); const verify = await this.client.onWhatsApp(...filteredNumbers);
const users: OnWhatsAppDto[] = await Promise.all( console.log('verify', verify);
jids.users.map(async (user) => { normalVerifiedUsers = await Promise.all(
normalUsers.map(async (user) => {
let numberVerified: (typeof verify)[0] | null = null; let numberVerified: (typeof verify)[0] | null = null;
const cached = cachedNumbers.find((cached) => cached.jidOptions.includes(user.jid.replace('+', ''))); const cached = cachedNumbers.find((cached) => cached.jidOptions.includes(user.jid.replace('+', '')));
if (cached) { if (cached) {
return { return new OnWhatsAppDto(
exists: true, cached.remoteJid,
jid: cached.remoteJid, true,
name: contacts.find((c) => c.remoteJid === cached.remoteJid)?.pushName, user.number,
number: user.number, contacts.find((c) => c.remoteJid === cached.remoteJid)?.pushName,
}; cached.lid || (cached.remoteJid.includes('@lid') ? cached.remoteJid.split('@')[1] : undefined),
);
} }
// Brazilian numbers // Brazilian numbers
@ -3185,7 +3199,7 @@ export class BaileysStartupService extends ChannelStartupService {
if (!numberVerified && (user.number.startsWith('52') || user.number.startsWith('54'))) { if (!numberVerified && (user.number.startsWith('52') || user.number.startsWith('54'))) {
let prefix = ''; let prefix = '';
if (user.number.startsWith('52')) { if (user.number.startsWith('52')) {
prefix = ''; prefix = '1';
} }
if (user.number.startsWith('54')) { if (user.number.startsWith('54')) {
prefix = '9'; prefix = '9';
@ -3208,19 +3222,47 @@ export class BaileysStartupService extends ChannelStartupService {
} }
const numberJid = numberVerified?.jid || user.jid; const numberJid = numberVerified?.jid || user.jid;
const lid =
return { typeof numberVerified?.lid === 'string'
exists: !!numberVerified?.exists, ? numberVerified.lid
jid: numberJid, : numberJid.includes('@lid')
name: contacts.find((c) => c.remoteJid === numberJid)?.pushName, ? numberJid.split('@')[1]
number: user.number, : undefined;
}; return new OnWhatsAppDto(
numberJid,
!!numberVerified?.exists,
user.number,
contacts.find((c) => c.remoteJid === numberJid)?.pushName,
lid,
);
}), }),
); );
}
await saveOnWhatsappCache(users.filter((user) => user.exists).map((user) => ({ remoteJid: user.jid }))); // For @lid numbers, always consider them as valid
const lidVerifiedUsers: OnWhatsAppDto[] = lidUsers.map((user) => {
return new OnWhatsAppDto(
user.jid,
true,
user.number,
contacts.find((c) => c.remoteJid === user.jid)?.pushName,
user.jid.split('@')[1],
);
});
onWhatsapp.push(...users); // Combine results
onWhatsapp.push(...normalVerifiedUsers, ...lidVerifiedUsers);
// Save to cache only valid numbers
await saveOnWhatsappCache(
onWhatsapp
.filter((user) => user.exists)
.map((user) => ({
remoteJid: user.jid,
jidOptions: user.jid.replace('+', ''),
lid: user.lid,
})),
);
return onWhatsapp; return onWhatsapp;
} }

View File

@ -46,6 +46,7 @@ export class ChatRouter extends RouterBroker {
super(); super();
this.router this.router
.post(this.routerPath('whatsappNumbers'), ...guards, async (req, res) => { .post(this.routerPath('whatsappNumbers'), ...guards, async (req, res) => {
try {
const response = await this.dataValidate<WhatsAppNumberDto>({ const response = await this.dataValidate<WhatsAppNumberDto>({
request: req, request: req,
schema: whatsappNumberSchema, schema: whatsappNumberSchema,
@ -54,6 +55,10 @@ export class ChatRouter extends RouterBroker {
}); });
return res.status(HttpStatus.OK).json(response); return res.status(HttpStatus.OK).json(response);
} catch (error) {
console.log(error);
return res.status(HttpStatus.BAD_REQUEST).json(error);
}
}) })
.post(this.routerPath('markMessageAsRead'), ...guards, async (req, res) => { .post(this.routerPath('markMessageAsRead'), ...guards, async (req, res) => {
const response = await this.dataValidate<ReadMessageDto>({ const response = await this.dataValidate<ReadMessageDto>({

View File

@ -52,7 +52,9 @@ function getAvailableNumbers(remoteJid: string) {
interface ISaveOnWhatsappCacheParams { interface ISaveOnWhatsappCacheParams {
remoteJid: string; remoteJid: string;
lid?: string;
} }
export async function saveOnWhatsappCache(data: ISaveOnWhatsappCacheParams[]) { export async function saveOnWhatsappCache(data: ISaveOnWhatsappCacheParams[]) {
if (configService.get<Database>('DATABASE').SAVE_DATA.IS_ON_WHATSAPP) { if (configService.get<Database>('DATABASE').SAVE_DATA.IS_ON_WHATSAPP) {
const upsertsQuery = data.map((item) => { const upsertsQuery = data.map((item) => {
@ -60,8 +62,15 @@ export async function saveOnWhatsappCache(data: ISaveOnWhatsappCacheParams[]) {
const numbersAvailable = getAvailableNumbers(remoteJid); const numbersAvailable = getAvailableNumbers(remoteJid);
return prismaRepository.isOnWhatsapp.upsert({ return prismaRepository.isOnWhatsapp.upsert({
create: { remoteJid: remoteJid, jidOptions: numbersAvailable.join(',') }, create: {
update: { jidOptions: numbersAvailable.join(',') }, remoteJid: remoteJid,
jidOptions: numbersAvailable.join(','),
lid: item.lid,
},
update: {
jidOptions: numbersAvailable.join(','),
lid: item.lid,
},
where: { remoteJid: remoteJid }, where: { remoteJid: remoteJid },
}); });
}); });
@ -75,6 +84,7 @@ export async function getOnWhatsappCache(remoteJids: string[]) {
remoteJid: string; remoteJid: string;
number: string; number: string;
jidOptions: string[]; jidOptions: string[];
lid?: string;
}[] = []; }[] = [];
if (configService.get<Database>('DATABASE').SAVE_DATA.IS_ON_WHATSAPP) { if (configService.get<Database>('DATABASE').SAVE_DATA.IS_ON_WHATSAPP) {
@ -93,6 +103,7 @@ export async function getOnWhatsappCache(remoteJids: string[]) {
remoteJid: item.remoteJid, remoteJid: item.remoteJid,
number: item.remoteJid.split('@')[0], number: item.remoteJid.split('@')[0],
jidOptions: item.jidOptions.split(','), jidOptions: item.jidOptions.split(','),
lid: item.lid,
})); }));
} }