From 332c3a04bb868c9d278c9fceef8873f9ad8bce75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Bosi?= <71827178+bosiraphael@users.noreply.github.com> Date: Tue, 22 Jul 2025 20:19:10 +0200 Subject: [PATCH] Fix critical bug in MessagingMessageListFetchService (#13350) ## Bug description All old messages were deleted after the first partial sync because the diff between the existing messages and the messages returned from the fetch was done considering that it was always a full sync (ie, that we always retrieve the full list of message ids). But in a partial sync, only the new messages appear in the list. This bug was introduced by https://github.com/twentyhq/twenty/pull/13302 when trying to merge the logic between the full sync and the partial sync. ## Fix The fix is to adapt the behavior to the type of sync, by looking at the presence of the sync cursor. --------- Co-authored-by: Guillim --- ...ssaging-message-list-fetch.service.spec.ts | 4 +++ .../messaging-message-list-fetch.service.ts | 32 +++++++++++++------ 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/services/messaging-message-list-fetch.service.spec.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/services/messaging-message-list-fetch.service.spec.ts index fd4e3b9ef..c7f21371b 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/services/messaging-message-list-fetch.service.spec.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/services/messaging-message-list-fetch.service.spec.ts @@ -97,6 +97,8 @@ describe('MessagingMessageListFetchService', () => { ], nextSyncCursor: 'new-google-history-id', folderId: undefined, + messageExternalIdsToDelete: [], + previousSyncCursor: 'google-sync-cursor', }, ]; } else { @@ -109,6 +111,8 @@ describe('MessagingMessageListFetchService', () => { ], nextSyncCursor: 'new-sync-cursor', folderId: 'inbox-folder-id', + messageExternalIdsToDelete: [], + previousSyncCursor: 'inbox-sync-cursor', }, ]; } diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/services/messaging-message-list-fetch.service.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/services/messaging-message-list-fetch.service.ts index 7d52f69ec..5bbf50eca 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/services/messaging-message-list-fetch.service.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/services/messaging-message-list-fetch.service.ts @@ -57,7 +57,13 @@ export class MessagingMessageListFetchService { } for (const messageList of messageLists) { - const { messageExternalIds, nextSyncCursor, folderId } = messageList; + const { + messageExternalIds, + nextSyncCursor, + folderId, + messageExternalIdsToDelete, + previousSyncCursor, + } = messageList; const messageChannelMessageAssociationRepository = await this.twentyORMManager.getRepository( @@ -84,17 +90,25 @@ export class MessagingMessageListFetchService { ), ); - const messageExternalIdsToDelete = - existingMessageChannelMessageAssociationsExternalIds.filter( - (existingMessageCMAExternalId) => - existingMessageCMAExternalId && - !messageExternalIds.includes(existingMessageCMAExternalId), - ); + const isFullSync = !previousSyncCursor; - if (messageExternalIdsToDelete.length) { + const additionalMessageExternalIdsToDelete = isFullSync + ? existingMessageChannelMessageAssociationsExternalIds.filter( + (existingMessageCMAExternalId) => + existingMessageCMAExternalId && + !messageExternalIds.includes(existingMessageCMAExternalId), + ) + : []; + + const allMessageExternalIdsToDelete = [ + ...messageExternalIdsToDelete, + ...additionalMessageExternalIdsToDelete, + ]; + + if (allMessageExternalIdsToDelete.length) { await messageChannelMessageAssociationRepository.delete({ messageChannelId: messageChannel.id, - messageExternalId: In(messageExternalIdsToDelete), + messageExternalId: In(allMessageExternalIdsToDelete), }); await this.messagingMessageCleanerService.cleanWorkspaceThreads(