Closes #5748 - Create feature flag - Add scope `https://www.googleapis.com/auth/profile.emails.read` when connecting an account - Get email aliases with google people API, store them in connectedAccount and refresh them before each message-import - Update the contact creation logic accordingly - Refactor --------- Co-authored-by: Charles Bochet <charles@twenty.com>
136 lines
5.4 KiB
TypeScript
136 lines
5.4 KiB
TypeScript
import { Injectable } from '@nestjs/common';
|
|
import { InjectRepository } from '@nestjs/typeorm';
|
|
import { EventEmitter2 } from '@nestjs/event-emitter';
|
|
|
|
import { EntityManager, Repository } from 'typeorm';
|
|
|
|
import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants';
|
|
import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service';
|
|
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
|
|
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
|
|
import {
|
|
CreateCompanyAndContactJobData,
|
|
CreateCompanyAndContactJob,
|
|
} from 'src/modules/connected-account/auto-companies-and-contacts-creation/jobs/create-company-and-contact.job';
|
|
import {
|
|
FeatureFlagEntity,
|
|
FeatureFlagKeys,
|
|
} from 'src/engine/core-modules/feature-flag/feature-flag.entity';
|
|
import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
|
import {
|
|
GmailMessage,
|
|
Participant,
|
|
ParticipantWithMessageId,
|
|
} from 'src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-message';
|
|
import { MessagingMessageService } from 'src/modules/messaging/common/services/messaging-message.service';
|
|
import { MessagingMessageParticipantService } from 'src/modules/messaging/common/services/messaging-message-participant.service';
|
|
import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator';
|
|
import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity';
|
|
|
|
@Injectable()
|
|
export class MessagingSaveMessagesAndEnqueueContactCreationService {
|
|
constructor(
|
|
private readonly workspaceDataSourceService: WorkspaceDataSourceService,
|
|
@InjectMessageQueue(MessageQueue.contactCreationQueue)
|
|
private readonly messageQueueService: MessageQueueService,
|
|
private readonly messageService: MessagingMessageService,
|
|
private readonly messageParticipantService: MessagingMessageParticipantService,
|
|
@InjectRepository(FeatureFlagEntity, 'core')
|
|
private readonly featureFlagRepository: Repository<FeatureFlagEntity>,
|
|
private readonly eventEmitter: EventEmitter2,
|
|
) {}
|
|
|
|
async saveMessagesAndEnqueueContactCreationJob(
|
|
messagesToSave: GmailMessage[],
|
|
messageChannel: MessageChannelWorkspaceEntity,
|
|
connectedAccount: ConnectedAccountWorkspaceEntity,
|
|
workspaceId: string,
|
|
) {
|
|
const workspaceDataSource =
|
|
await this.workspaceDataSourceService.connectToWorkspaceDataSource(
|
|
workspaceId,
|
|
);
|
|
|
|
const isContactCreationForSentAndReceivedEmailsEnabledFeatureFlag =
|
|
await this.featureFlagRepository.findOneBy({
|
|
workspaceId: workspaceId,
|
|
key: FeatureFlagKeys.IsContactCreationForSentAndReceivedEmailsEnabled,
|
|
value: true,
|
|
});
|
|
|
|
const emailAliases = connectedAccount.emailAliases?.split(',') || [];
|
|
|
|
const isContactCreationForSentAndReceivedEmailsEnabled =
|
|
isContactCreationForSentAndReceivedEmailsEnabledFeatureFlag?.value;
|
|
|
|
let savedMessageParticipants: MessageParticipantWorkspaceEntity[] = [];
|
|
|
|
const participantsWithMessageId = await workspaceDataSource?.transaction(
|
|
async (transactionManager: EntityManager) => {
|
|
const messageExternalIdsAndIdsMap =
|
|
await this.messageService.saveMessagesWithinTransaction(
|
|
messagesToSave,
|
|
connectedAccount,
|
|
messageChannel.id,
|
|
workspaceId,
|
|
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 ||
|
|
'';
|
|
|
|
return {
|
|
...participant,
|
|
messageId,
|
|
shouldCreateContact:
|
|
messageChannel.isContactAutoCreationEnabled &&
|
|
(isContactCreationForSentAndReceivedEmailsEnabled ||
|
|
emailAliases.includes(fromHandle)) &&
|
|
!emailAliases.includes(participant.handle),
|
|
};
|
|
})
|
|
: [];
|
|
});
|
|
|
|
savedMessageParticipants =
|
|
await this.messageParticipantService.saveMessageParticipants(
|
|
participantsWithMessageId,
|
|
workspaceId,
|
|
transactionManager,
|
|
);
|
|
|
|
return participantsWithMessageId;
|
|
},
|
|
);
|
|
|
|
this.eventEmitter.emit(`messageParticipant.matched`, {
|
|
workspaceId,
|
|
workspaceMemberId: connectedAccount.accountOwnerId,
|
|
messageParticipants: savedMessageParticipants,
|
|
});
|
|
|
|
if (messageChannel.isContactAutoCreationEnabled) {
|
|
const contactsToCreate = participantsWithMessageId.filter(
|
|
(participant) => participant.shouldCreateContact,
|
|
);
|
|
|
|
await this.messageQueueService.add<CreateCompanyAndContactJobData>(
|
|
CreateCompanyAndContactJob.name,
|
|
{
|
|
workspaceId,
|
|
connectedAccount,
|
|
contactsToCreate,
|
|
},
|
|
);
|
|
}
|
|
}
|
|
}
|