Emit message event with actual message object (#11548)

Events were emitted with the wrong object. We were using
messageWithParticipant instead of actual message object
This commit is contained in:
Thomas Trompette
2025-04-14 13:49:19 +02:00
committed by GitHub
parent abecdbafc1
commit 69a00eaaf6
3 changed files with 95 additions and 78 deletions

View File

@ -17,7 +17,10 @@ export class MessagingMessageService {
messages: MessageWithParticipants[],
messageChannelId: string,
transactionManager: EntityManager,
): Promise<Map<string, string>> {
): Promise<{
createdMessages: Partial<MessageWorkspaceEntity>[];
messageExternalIdsAndIdsMap: Map<string, string>;
}> {
const messageChannelMessageAssociationRepository =
await this.twentyORMManager.getRepository<MessageChannelMessageAssociationWorkspaceEntity>(
'messageChannelMessageAssociation',
@ -34,6 +37,7 @@ export class MessagingMessageService {
);
const messageExternalIdsAndIdsMap = new Map<string, string>();
const createdMessages: Partial<MessageWorkspaceEntity>[] = [];
for (const message of messages) {
const existingMessageChannelMessageAssociation =
@ -101,18 +105,18 @@ export class MessagingMessageService {
}
const newMessageId = v4();
const messageToCreate = {
id: newMessageId,
headerMessageId: message.headerMessageId,
subject: message.subject,
receivedAt: message.receivedAt,
text: message.text,
messageThreadId: newOrExistingMessageThreadId,
};
await messageRepository.insert(
{
id: newMessageId,
headerMessageId: message.headerMessageId,
subject: message.subject,
receivedAt: message.receivedAt,
text: message.text,
messageThreadId: newOrExistingMessageThreadId,
},
transactionManager,
);
await messageRepository.insert(messageToCreate, transactionManager);
createdMessages.push(messageToCreate);
messageExternalIdsAndIdsMap.set(message.externalId, newMessageId);
@ -128,6 +132,9 @@ export class MessagingMessageService {
);
}
return messageExternalIdsAndIdsMap;
return {
createdMessages,
messageExternalIdsAndIdsMap,
};
}
}

View File

@ -119,12 +119,16 @@ describe('MessagingSaveMessagesAndEnqueueContactCreationService', () => {
{
provide: MessagingMessageService,
useValue: {
saveMessagesWithinTransaction: jest.fn().mockResolvedValue(
new Map([
saveMessagesWithinTransaction: jest.fn().mockResolvedValue({
messageExternalIdsAndIdsMap: new Map([
['message-1', 'db-message-id-1'],
['message-2', 'db-message-id-2'],
]),
),
createdMessages: [
{ id: 'db-message-id-1' },
{ id: 'db-message-id-2' },
],
}),
},
},
{

View File

@ -53,70 +53,76 @@ export class MessagingSaveMessagesAndEnqueueContactCreationService {
const workspaceDataSource = await this.twentyORMManager.getDatasource();
const participantsWithMessageId = await workspaceDataSource?.transaction(
async (transactionManager: EntityManager) => {
const messageExternalIdsAndIdsMap =
await this.messageService.saveMessagesWithinTransaction(
messagesToSave,
messageChannel.id,
const createdMessagesWithParticipants =
await workspaceDataSource?.transaction(
async (transactionManager: EntityManager) => {
const { messageExternalIdsAndIdsMap, createdMessages } =
await this.messageService.saveMessagesWithinTransaction(
messagesToSave,
messageChannel.id,
transactionManager,
);
const participantsWithMessageId: (ParticipantWithMessageId & {
shouldCreateContact: boolean;
})[] = messagesToSave.flatMap((message) => {
const messageId = messageExternalIdsAndIdsMap.get(
message.externalId,
);
return messageId
? message.participants.map((participant: Participant) => {
const fromHandle =
message.participants.find((p) => p.role === 'from')
?.handle || '';
const isMessageSentByConnectedAccount =
handleAliases.includes(fromHandle) ||
fromHandle === connectedAccount.handle;
const isParticipantConnectedAccount =
handleAliases.includes(participant.handle) ||
participant.handle === connectedAccount.handle;
const isExcludedByNonProfessionalEmails =
messageChannel.excludeNonProfessionalEmails &&
!isWorkEmail(participant.handle);
const isExcludedByGroupEmails =
messageChannel.excludeGroupEmails &&
isGroupEmail(participant.handle);
const shouldCreateContact =
!!participant.handle &&
!isParticipantConnectedAccount &&
!isExcludedByNonProfessionalEmails &&
!isExcludedByGroupEmails &&
(messageChannel.contactAutoCreationPolicy ===
MessageChannelContactAutoCreationPolicy.SENT_AND_RECEIVED ||
(messageChannel.contactAutoCreationPolicy ===
MessageChannelContactAutoCreationPolicy.SENT &&
isMessageSentByConnectedAccount));
return {
...participant,
messageId,
shouldCreateContact,
};
})
: [];
});
await this.messageParticipantService.saveMessageParticipants(
participantsWithMessageId,
transactionManager,
);
const participantsWithMessageId: (ParticipantWithMessageId & {
shouldCreateContact: boolean;
})[] = messagesToSave.flatMap((message) => {
const messageId = messageExternalIdsAndIdsMap.get(message.externalId);
return { participantsWithMessageId, createdMessages };
},
);
return messageId
? message.participants.map((participant: Participant) => {
const fromHandle =
message.participants.find((p) => p.role === 'from')?.handle ||
'';
const isMessageSentByConnectedAccount =
handleAliases.includes(fromHandle) ||
fromHandle === connectedAccount.handle;
const isParticipantConnectedAccount =
handleAliases.includes(participant.handle) ||
participant.handle === connectedAccount.handle;
const isExcludedByNonProfessionalEmails =
messageChannel.excludeNonProfessionalEmails &&
!isWorkEmail(participant.handle);
const isExcludedByGroupEmails =
messageChannel.excludeGroupEmails &&
isGroupEmail(participant.handle);
const shouldCreateContact =
!!participant.handle &&
!isParticipantConnectedAccount &&
!isExcludedByNonProfessionalEmails &&
!isExcludedByGroupEmails &&
(messageChannel.contactAutoCreationPolicy ===
MessageChannelContactAutoCreationPolicy.SENT_AND_RECEIVED ||
(messageChannel.contactAutoCreationPolicy ===
MessageChannelContactAutoCreationPolicy.SENT &&
isMessageSentByConnectedAccount));
return {
...participant,
messageId,
shouldCreateContact,
};
})
: [];
});
await this.messageParticipantService.saveMessageParticipants(
participantsWithMessageId,
transactionManager,
);
return participantsWithMessageId;
},
);
const { participantsWithMessageId, createdMessages } =
createdMessagesWithParticipants;
const messageMetadata = await this.objectMetadataRepository.findOneOrFail({
where: { nameSingular: 'message', workspaceId },
@ -125,9 +131,9 @@ export class MessagingSaveMessagesAndEnqueueContactCreationService {
this.workspaceEventEmitter.emitDatabaseBatchEvent({
objectMetadataNameSingular: 'message',
action: DatabaseEventAction.CREATED,
events: messagesToSave.map((message) => {
events: createdMessages.map((message) => {
return {
recordId: message.headerMessageId,
recordId: message.id ?? '',
objectMetadata: messageMetadata,
properties: {
after: message,