Skip to content

Commit f38f3e5

Browse files
Merge pull request #958 from jesus-chacon/features/last_message_in_chat
Added last message to fetch chats
2 parents c29d20e + 394c091 commit f38f3e5

File tree

2 files changed

+194
-57
lines changed

2 files changed

+194
-57
lines changed

src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts

Lines changed: 84 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -667,7 +667,6 @@ export class BaileysStartupService extends ChannelStartupService {
667667
instanceId: this.instanceId,
668668
remoteJid: chat.id,
669669
name: chat.name,
670-
unreadMessages: typeof chat.unreadCount === 'number' ? chat.unreadCount : 0,
671670
},
672671
data: { remoteJid: chat.id },
673672
});
@@ -985,8 +984,10 @@ export class BaileysStartupService extends ChannelStartupService {
985984
for (const received of messages) {
986985
if (received.message?.conversation || received.message?.extendedTextMessage?.text) {
987986
const text = received.message?.conversation || received.message?.extendedTextMessage?.text;
987+
988988
if (text == 'requestPlaceholder' && !requestId) {
989989
const messageId = await this.client.requestPlaceholderResend(received.key);
990+
990991
console.log('requested placeholder resync, id=', messageId);
991992
} else if (requestId) {
992993
console.log('Message received from phone, id=', requestId, received);
@@ -1020,6 +1021,7 @@ export class BaileysStartupService extends ChannelStartupService {
10201021
message: received,
10211022
retry: 0,
10221023
});
1024+
10231025
continue;
10241026
}
10251027

@@ -1036,15 +1038,15 @@ export class BaileysStartupService extends ChannelStartupService {
10361038
received.message?.pollUpdateMessage ||
10371039
!received?.message
10381040
) {
1039-
return;
1041+
continue;
10401042
}
10411043

10421044
if (Long.isLong(received.messageTimestamp)) {
10431045
received.messageTimestamp = received.messageTimestamp?.toNumber();
10441046
}
10451047

10461048
if (settings?.groupsIgnore && received.key.remoteJid.includes('@g.us')) {
1047-
return;
1049+
continue;
10481050
}
10491051

10501052
const messageRaw = this.prepareMessage(received);
@@ -1107,6 +1109,17 @@ export class BaileysStartupService extends ChannelStartupService {
11071109
data: messageRaw,
11081110
});
11091111

1112+
if (received.key.fromMe === false) {
1113+
if (msg.status === status[3]) {
1114+
this.logger.log(`Update not read messages ${received.key.remoteJid}`);
1115+
// is received not read message
1116+
await this.updateChatUnreadMessages(received.key.remoteJid);
1117+
} else if (msg.status === status[4]) {
1118+
this.logger.log(`Update readed messages ${received.key.remoteJid} - ${msg.messageTimestamp}`);
1119+
this.updateMessagesReadedByTimestamp(received.key.remoteJid, msg.messageTimestamp);
1120+
}
1121+
}
1122+
11101123
if (isMedia) {
11111124
if (this.configService.get<S3>('S3').ENABLE) {
11121125
try {
@@ -1119,11 +1132,8 @@ export class BaileysStartupService extends ChannelStartupService {
11191132
);
11201133

11211134
const { buffer, mediaType, fileName, size } = media;
1122-
11231135
const mimetype = mime.getType(fileName).toString();
1124-
11251136
const fullName = join(`${this.instance.id}`, received.key.remoteJid, mediaType, fileName);
1126-
11271137
await s3Service.uploadFile(fullName, buffer, size.fileLength?.low, {
11281138
'Content-Type': mimetype,
11291139
});
@@ -1192,7 +1202,7 @@ export class BaileysStartupService extends ChannelStartupService {
11921202
};
11931203

11941204
if (contactRaw.remoteJid === 'status@broadcast') {
1195-
return;
1205+
continue;
11961206
}
11971207

11981208
if (contact) {
@@ -1213,7 +1223,7 @@ export class BaileysStartupService extends ChannelStartupService {
12131223
update: contactRaw,
12141224
});
12151225

1216-
return;
1226+
continue;
12171227
}
12181228

12191229
this.sendDataWebhook(Events.CONTACTS_UPSERT, contactRaw);
@@ -1240,11 +1250,11 @@ export class BaileysStartupService extends ChannelStartupService {
12401250
},
12411251

12421252
'messages.update': async (args: WAMessageUpdate[], settings: any) => {
1243-
const unreadChatToUpdate: Record<string, number> = {}; // {remoteJid: readedMessages}
1253+
const readChatToUpdate: Record<string, true> = {}; // {remoteJid: true}
12441254

12451255
for await (const { key, update } of args) {
12461256
if (settings?.groupsIgnore && key.remoteJid?.includes('@g.us')) {
1247-
return;
1257+
continue;
12481258
}
12491259

12501260
if (status[update.status] === 'READ' && key.fromMe) {
@@ -1259,6 +1269,7 @@ export class BaileysStartupService extends ChannelStartupService {
12591269

12601270
if (key.remoteJid !== 'status@broadcast') {
12611271
let pollUpdates: any;
1272+
12621273
if (update.pollUpdates) {
12631274
const pollCreation = await this.getMessage(key);
12641275

@@ -1281,7 +1292,7 @@ export class BaileysStartupService extends ChannelStartupService {
12811292
});
12821293

12831294
if (!findMessage) {
1284-
return;
1295+
continue;
12851296
}
12861297

12871298
if (update.message === null && update.status === undefined) {
@@ -1310,15 +1321,18 @@ export class BaileysStartupService extends ChannelStartupService {
13101321
);
13111322
}
13121323

1313-
return;
1324+
continue;
13141325
} else if (update.status !== undefined && status[update.status] !== findMessage.status) {
1315-
if (!unreadChatToUpdate[key.remoteJid!]) {
1316-
unreadChatToUpdate[key.remoteJid!] = 0;
1317-
}
1326+
if (!key.fromMe && key.remoteJid) {
1327+
readChatToUpdate[key.remoteJid] = true;
13181328

1319-
unreadChatToUpdate[key.remoteJid!]++;
1329+
if (status[update.status] === status[4]) {
1330+
this.logger.log(`Update as read ${key.remoteJid} - ${findMessage.messageTimestamp}`);
1331+
this.updateMessagesReadedByTimestamp(key.remoteJid, findMessage.messageTimestamp);
1332+
}
1333+
}
13201334

1321-
this.prismaRepository.message.update({
1335+
await this.prismaRepository.message.update({
13221336
where: { id: findMessage.id },
13231337
data: { status: status[update.status] },
13241338
});
@@ -1344,16 +1358,7 @@ export class BaileysStartupService extends ChannelStartupService {
13441358
}
13451359
}
13461360

1347-
for await (const [remoteJid, unreadMessages] of Object.entries(unreadChatToUpdate)) {
1348-
const chat = await this.prismaRepository.chat.findFirst({ where: { remoteJid } });
1349-
1350-
if (chat) {
1351-
this.prismaRepository.chat.update({
1352-
where: { id: chat.id },
1353-
data: { unreadMessages: Math.max(0, chat.unreadMessages - unreadMessages) },
1354-
});
1355-
}
1356-
}
1361+
await Promise.all(Object.keys(readChatToUpdate).map((remoteJid) => this.updateChatUnreadMessages(remoteJid)));
13571362
},
13581363
};
13591364

@@ -3713,6 +3718,10 @@ export class BaileysStartupService extends ChannelStartupService {
37133718
source: getDevice(message.key.id),
37143719
};
37153720

3721+
if (!messageRaw.status && message.key.fromMe === false) {
3722+
messageRaw.status = status[3]; // DELIVERED MESSAGE
3723+
}
3724+
37163725
if (messageRaw.message.extendedTextMessage) {
37173726
messageRaw.messageType = 'conversation';
37183727
messageRaw.message.conversation = messageRaw.message.extendedTextMessage.text;
@@ -3740,4 +3749,52 @@ export class BaileysStartupService extends ChannelStartupService {
37403749
task.start();
37413750
}
37423751
}
3752+
3753+
private async updateMessagesReadedByTimestamp(remoteJid: string, timestamp?: number): Promise<number> {
3754+
if (timestamp === undefined || timestamp === null) return 0;
3755+
3756+
const result = await this.prismaRepository.message.updateMany({
3757+
where: {
3758+
AND: [
3759+
{ key: { path: ['remoteJid'], equals: remoteJid } },
3760+
{ key: { path: ['fromMe'], equals: false } },
3761+
{ messageTimestamp: { lte: timestamp } },
3762+
{
3763+
OR: [{ status: null }, { status: status[3] }],
3764+
},
3765+
],
3766+
},
3767+
data: { status: status[4] },
3768+
});
3769+
3770+
if (result) {
3771+
return result.count;
3772+
}
3773+
3774+
return 0;
3775+
}
3776+
3777+
private async updateChatUnreadMessages(remoteJid: string): Promise<number> {
3778+
const [chat, unreadMessages] = await Promise.all([
3779+
this.prismaRepository.chat.findFirst({ where: { remoteJid } }),
3780+
this.prismaRepository.message.count({
3781+
where: {
3782+
AND: [
3783+
{ key: { path: ['remoteJid'], equals: remoteJid } },
3784+
{ key: { path: ['fromMe'], equals: false } },
3785+
{ status: { equals: status[3] } },
3786+
],
3787+
},
3788+
}),
3789+
]);
3790+
3791+
if (chat && chat.unreadMessages !== unreadMessages) {
3792+
await this.prismaRepository.chat.update({
3793+
where: { id: chat.id },
3794+
data: { unreadMessages },
3795+
});
3796+
}
3797+
3798+
return unreadMessages;
3799+
}
37433800
}

src/api/services/channel.service.ts

Lines changed: 110 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { Logger } from '@config/logger.config';
1414
import { NotFoundException } from '@exceptions';
1515
import { Contact, Message } from '@prisma/client';
1616
import { WASocket } from 'baileys';
17+
import { isArray } from 'class-validator';
1718
import EventEmitter2 from 'eventemitter2';
1819
import { v4 } from 'uuid';
1920

@@ -627,35 +628,114 @@ export class ChannelStartupService {
627628
: this.createJid(query.where?.remoteJid)
628629
: null;
629630

630-
const result = await this.prismaRepository.$queryRaw`
631-
SELECT
632-
"Chat"."id",
633-
"Chat"."remoteJid",
634-
"Chat"."name",
635-
"Chat"."labels",
636-
"Chat"."createdAt",
637-
"Chat"."updatedAt",
638-
"Contact"."pushName",
639-
"Contact"."profilePicUrl",
640-
"Contact"."unreadMessages"
641-
FROM "Chat"
642-
INNER JOIN "Message" ON "Chat"."remoteJid" = "Message"."key"->>'remoteJid'
643-
LEFT JOIN "Contact" ON "Chat"."remoteJid" = "Contact"."remoteJid"
644-
WHERE "Chat"."instanceId" = ${this.instanceId}
645-
${remoteJid ? 'AND "Chat"."remoteJid" = ${remoteJid}' : ''}
646-
GROUP BY
647-
"Chat"."id",
648-
"Chat"."remoteJid",
649-
"Chat"."name",
650-
"Chat"."labels",
651-
"Chat"."createdAt",
652-
"Chat"."updatedAt",
653-
"Contact"."pushName",
654-
"Contact"."profilePicUrl",
655-
"Contact"."unreadMessages"
656-
ORDER BY "Chat"."updatedAt" DESC;
657-
`;
658-
659-
return result;
631+
let results = [];
632+
633+
if (!remoteJid) {
634+
results = await this.prismaRepository.$queryRaw`
635+
SELECT
636+
"Chat"."id",
637+
"Chat"."remoteJid",
638+
"Chat"."name",
639+
"Chat"."labels",
640+
"Chat"."createdAt",
641+
"Chat"."updatedAt",
642+
"Contact"."pushName",
643+
"Contact"."profilePicUrl",
644+
"Chat"."unreadMessages",
645+
(ARRAY_AGG("Message"."id" ORDER BY "Message"."messageTimestamp" DESC))[1] AS last_message_id,
646+
(ARRAY_AGG("Message"."key" ORDER BY "Message"."messageTimestamp" DESC))[1] AS last_message_key,
647+
(ARRAY_AGG("Message"."pushName" ORDER BY "Message"."messageTimestamp" DESC))[1] AS last_message_pushName,
648+
(ARRAY_AGG("Message"."participant" ORDER BY "Message"."messageTimestamp" DESC))[1] AS last_message_participant,
649+
(ARRAY_AGG("Message"."messageType" ORDER BY "Message"."messageTimestamp" DESC))[1] AS last_message_messageType,
650+
(ARRAY_AGG("Message"."message" ORDER BY "Message"."messageTimestamp" DESC))[1] AS last_message_message,
651+
(ARRAY_AGG("Message"."contextInfo" ORDER BY "Message"."messageTimestamp" DESC))[1] AS last_message_contextInfo,
652+
(ARRAY_AGG("Message"."source" ORDER BY "Message"."messageTimestamp" DESC))[1] AS last_message_source,
653+
(ARRAY_AGG("Message"."messageTimestamp" ORDER BY "Message"."messageTimestamp" DESC))[1] AS last_message_messageTimestamp,
654+
(ARRAY_AGG("Message"."instanceId" ORDER BY "Message"."messageTimestamp" DESC))[1] AS last_message_instanceId,
655+
(ARRAY_AGG("Message"."sessionId" ORDER BY "Message"."messageTimestamp" DESC))[1] AS last_message_sessionId,
656+
(ARRAY_AGG("Message"."status" ORDER BY "Message"."messageTimestamp" DESC))[1] AS last_message_status
657+
FROM "Chat"
658+
LEFT JOIN "Message" ON "Message"."key"->>'remoteJid' = "Chat"."remoteJid"
659+
LEFT JOIN "Contact" ON "Chat"."remoteJid" = "Contact"."remoteJid"
660+
WHERE
661+
"Chat"."instanceId" = ${this.instanceId}
662+
GROUP BY
663+
"Chat"."id",
664+
"Chat"."remoteJid",
665+
"Contact"."id",
666+
"Message"."messageTimestamp"
667+
ORDER BY "Message"."messageTimestamp" DESC NULLS LAST, "Chat"."updatedAt" DESC;
668+
`;
669+
} else {
670+
results = await this.prismaRepository.$queryRaw`
671+
SELECT
672+
"Chat"."id",
673+
"Chat"."remoteJid",
674+
"Chat"."name",
675+
"Chat"."labels",
676+
"Chat"."createdAt",
677+
"Chat"."updatedAt",
678+
"Contact"."pushName",
679+
"Contact"."profilePicUrl",
680+
"Chat"."unreadMessages",
681+
(ARRAY_AGG("Message"."id" ORDER BY "Message"."messageTimestamp" DESC))[1] AS last_message_id,
682+
(ARRAY_AGG("Message"."key" ORDER BY "Message"."messageTimestamp" DESC))[1] AS last_message_key,
683+
(ARRAY_AGG("Message"."pushName" ORDER BY "Message"."messageTimestamp" DESC))[1] AS last_message_pushName,
684+
(ARRAY_AGG("Message"."participant" ORDER BY "Message"."messageTimestamp" DESC))[1] AS last_message_participant,
685+
(ARRAY_AGG("Message"."messageType" ORDER BY "Message"."messageTimestamp" DESC))[1] AS last_message_messageType,
686+
(ARRAY_AGG("Message"."message" ORDER BY "Message"."messageTimestamp" DESC))[1] AS last_message_message,
687+
(ARRAY_AGG("Message"."contextInfo" ORDER BY "Message"."messageTimestamp" DESC))[1] AS last_message_contextInfo,
688+
(ARRAY_AGG("Message"."source" ORDER BY "Message"."messageTimestamp" DESC))[1] AS last_message_source,
689+
(ARRAY_AGG("Message"."messageTimestamp" ORDER BY "Message"."messageTimestamp" DESC))[1] AS last_message_messageTimestamp,
690+
(ARRAY_AGG("Message"."instanceId" ORDER BY "Message"."messageTimestamp" DESC))[1] AS last_message_instanceId,
691+
(ARRAY_AGG("Message"."sessionId" ORDER BY "Message"."messageTimestamp" DESC))[1] AS last_message_sessionId,
692+
(ARRAY_AGG("Message"."status" ORDER BY "Message"."messageTimestamp" DESC))[1] AS last_message_status
693+
FROM "Chat"
694+
LEFT JOIN "Message" ON "Message"."key"->>'remoteJid' = "Chat"."remoteJid"
695+
LEFT JOIN "Contact" ON "Chat"."remoteJid" = "Contact"."remoteJid"
696+
WHERE
697+
"Chat"."instanceId" = ${this.instanceId} AND "Chat"."remoteJid" = ${remoteJid}
698+
GROUP BY
699+
"Chat"."id",
700+
"Chat"."remoteJid",
701+
"Contact"."id",
702+
"Message"."messageTimestamp"
703+
ORDER BY "Message"."messageTimestamp" DESC NULLS LAST, "Chat"."updatedAt" DESC;
704+
`;
705+
}
706+
707+
if (results && isArray(results) && results.length > 0) {
708+
return results.map((chat) => {
709+
return {
710+
id: chat.id,
711+
remoteJid: chat.remoteJid,
712+
name: chat.name,
713+
labels: chat.labels,
714+
createdAt: chat.createdAt,
715+
updatedAt: chat.updatedAt,
716+
pushName: chat.pushName,
717+
profilePicUrl: chat.profilePicUrl,
718+
unreadMessages: chat.unreadMessages,
719+
lastMessage: chat.last_message_id
720+
? {
721+
id: chat.last_message_id,
722+
key: chat.last_message_key,
723+
pushName: chat.last_message_pushName,
724+
participant: chat.last_message_participant,
725+
messageType: chat.last_message_messageType,
726+
message: chat.last_message_message,
727+
contextInfo: chat.last_message_contextInfo,
728+
source: chat.last_message_source,
729+
messageTimestamp: chat.last_message_messageTimestamp,
730+
instanceId: chat.last_message_instanceId,
731+
sessionId: chat.last_message_sessionId,
732+
status: chat.last_message_status,
733+
}
734+
: undefined,
735+
};
736+
});
737+
}
738+
739+
return [];
660740
}
661741
}

0 commit comments

Comments
 (0)