Skip to content

Commit

Permalink
Introduce a new feature flag for contact creation (twentyhq#5570)
Browse files Browse the repository at this point in the history
Introduce new feature flag
`IS_CONTACT_CREATION_FOR_SENT_AND_RECEIVED_EMAILS_ENABLED` to allow
contacts to be created for sent and received emails.
  • Loading branch information
bosiraphael committed May 24, 2024
1 parent a017847 commit 936ac40
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ export const seedFeatureFlags = async (
workspaceId: workspaceId,
value: true,
},
{
key: FeatureFlagKeys.IsContactCreationForSentAndReceivedEmailsEnabled,
workspaceId: workspaceId,
value: true,
},
])
.execute();
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export enum FeatureFlagKeys {
IsStripeIntegrationEnabled = 'IS_STRIPE_INTEGRATION_ENABLED',
IsGmailSyncV2Enabled = 'IS_GMAIL_SYNC_V2_ENABLED',
IsLinksFieldEnabled = 'IS_LINKS_FIELD_ENABLED',
IsContactCreationForSentAndReceivedEmailsEnabled = 'IS_CONTACT_CREATION_FOR_SENT_AND_RECEIVED_EMAILS_ENABLED',
}

@Entity({ name: 'featureFlag', schema: 'core' })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export class AddStandardIdCommand extends CommandRunner {
IS_STRIPE_INTEGRATION_ENABLED: false,
IS_GMAIL_SYNC_V2_ENABLED: true,
IS_LINKS_FIELD_ENABLED: true,
IS_CONTACT_CREATION_FOR_SENT_AND_RECEIVED_EMAILS_ENABLED: true,
},
);
const standardFieldMetadataCollection = this.standardFieldFactory.create(
Expand All @@ -76,6 +77,7 @@ export class AddStandardIdCommand extends CommandRunner {
IS_STRIPE_INTEGRATION_ENABLED: false,
IS_GMAIL_SYNC_V2_ENABLED: true,
IS_LINKS_FIELD_ENABLED: true,
IS_CONTACT_CREATION_FOR_SENT_AND_RECEIVED_EMAILS_ENABLED: true,
},
);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';

import { Repository } from 'typeorm';

import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface';

import {
FeatureFlagEntity,
FeatureFlagKeys,
} from 'src/engine/core-modules/feature-flag/feature-flag.entity';
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
import { CreateCompanyAndContactService } from 'src/modules/connected-account/auto-companies-and-contacts-creation/services/create-company-and-contact.service';
import { MessageChannelRepository } from 'src/modules/messaging/repositories/message-channel.repository';
Expand All @@ -27,6 +34,8 @@ export class MessagingCreateCompanyAndContactAfterSyncJob
private readonly messageChannelService: MessageChannelRepository,
@InjectObjectMetadataRepository(MessageParticipantWorkspaceEntity)
private readonly messageParticipantRepository: MessageParticipantRepository,
@InjectRepository(FeatureFlagEntity, 'core')
private readonly featureFlagRepository: Repository<FeatureFlagEntity>,
) {}

async handle(
Expand All @@ -48,11 +57,25 @@ export class MessagingCreateCompanyAndContactAfterSyncJob
return;
}

const contactsToCreate =
await this.messageParticipantRepository.getByMessageChannelIdWithoutPersonIdAndWorkspaceMemberIdAndMessageOutgoing(
messageChannelId,
workspaceId,
);
const isContactCreationForSentAndReceivedEmailsEnabledFeatureFlag =
await this.featureFlagRepository.findOneBy({
workspaceId: workspaceId,
key: FeatureFlagKeys.IsContactCreationForSentAndReceivedEmailsEnabled,
value: true,
});

const isContactCreationForSentAndReceivedEmailsEnabled =
isContactCreationForSentAndReceivedEmailsEnabledFeatureFlag?.value;

const contactsToCreate = isContactCreationForSentAndReceivedEmailsEnabled
? await this.messageParticipantRepository.getByMessageChannelIdWithoutPersonIdAndWorkspaceMemberId(
messageChannelId,
workspaceId,
)
: await this.messageParticipantRepository.getByMessageChannelIdWithoutPersonIdAndWorkspaceMemberIdAndMessageOutgoing(
messageChannelId,
workspaceId,
);

await this.createCompanyAndContactService.createCompaniesAndContactsAndUpdateParticipants(
handle,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,41 @@ export class MessageParticipantRepository {
return messageParticipants;
}

public async getByMessageChannelIdWithoutPersonIdAndWorkspaceMemberId(
messageChannelId: string,
workspaceId: string,
transactionManager?: EntityManager,
): Promise<ParticipantWithId[]> {
if (!messageChannelId || !workspaceId) {
return [];
}

const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId);

const messageParticipants: ParticipantWithId[] =
await this.workspaceDataSourceService.executeRawQuery(
`SELECT "messageParticipant".id,
"messageParticipant"."role",
"messageParticipant"."handle",
"messageParticipant"."displayName",
"messageParticipant"."personId",
"messageParticipant"."workspaceMemberId",
"messageParticipant"."messageId"
FROM ${dataSourceSchema}."messageParticipant" "messageParticipant"
LEFT JOIN ${dataSourceSchema}."message" ON "messageParticipant"."messageId" = ${dataSourceSchema}."message"."id"
LEFT JOIN ${dataSourceSchema}."messageChannelMessageAssociation" ON ${dataSourceSchema}."messageChannelMessageAssociation"."messageId" = ${dataSourceSchema}."message"."id"
WHERE ${dataSourceSchema}."messageChannelMessageAssociation"."messageChannelId" = $1
AND "messageParticipant"."personId" IS NULL
AND "messageParticipant"."workspaceMemberId" IS NULL`,
[messageChannelId],
workspaceId,
transactionManager,
);

return messageParticipants;
}

public async getWithoutPersonIdAndWorkspaceMemberId(
workspaceId: string,
transactionManager?: EntityManager,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module';
import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
Expand All @@ -24,6 +26,7 @@ import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/standard-ob
MessageModule,
MessageParticipantModule,
SetMessageChannelSyncStatusModule,
TypeOrmModule.forFeature([FeatureFlagEntity], 'core'),
],
providers: [
GmailMessagesImportService,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Inject, Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';

import { EntityManager } from 'typeorm';
import { EntityManager, Repository } from 'typeorm';

import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository';
Expand Down Expand Up @@ -31,6 +32,10 @@ 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';

@Injectable()
export class GmailMessagesImportService {
Expand All @@ -49,6 +54,8 @@ export class GmailMessagesImportService {
private readonly messageQueueService: MessageQueueService,
private readonly messageService: MessageService,
private readonly messageParticipantService: MessageParticipantService,
@InjectRepository(FeatureFlagEntity, 'core')
private readonly featureFlagRepository: Repository<FeatureFlagEntity>,
) {}

async fetchMessageContentFromCache(
Expand Down Expand Up @@ -171,6 +178,16 @@ export class GmailMessagesImportService {

const messageQueries = createQueriesFromMessageIds(messageIdsToFetch);

const isContactCreationForSentAndReceivedEmailsEnabledFeatureFlag =
await this.featureFlagRepository.findOneBy({
workspaceId: workspaceId,
key: FeatureFlagKeys.IsContactCreationForSentAndReceivedEmailsEnabled,
value: true,
});

const isContactCreationForSentAndReceivedEmailsEnabled =
isContactCreationForSentAndReceivedEmailsEnabledFeatureFlag?.value;

try {
const messagesToSave =
await this.fetchMessagesByBatchesService.fetchAllMessages(
Expand Down Expand Up @@ -214,8 +231,9 @@ export class GmailMessagesImportService {
messageId,
shouldCreateContact:
gmailMessageChannel.isContactAutoCreationEnabled &&
message.participants.find((p) => p.role === 'from')
?.handle === connectedAccount.handle,
(isContactCreationForSentAndReceivedEmailsEnabled ||
message.participants.find((p) => p.role === 'from')
?.handle === connectedAccount.handle),
}))
: [];
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Injectable, Inject } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';

import { EntityManager } from 'typeorm';
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';
Expand All @@ -18,6 +19,10 @@ 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';

@Injectable()
export class SaveMessagesAndEnqueueContactCreationService {
Expand All @@ -27,6 +32,8 @@ export class SaveMessagesAndEnqueueContactCreationService {
private readonly messageQueueService: MessageQueueService,
private readonly messageService: MessageService,
private readonly messageParticipantService: MessageParticipantService,
@InjectRepository(FeatureFlagEntity, 'core')
private readonly featureFlagRepository: Repository<FeatureFlagEntity>,
) {}

async saveMessagesAndEnqueueContactCreationJob(
Expand All @@ -40,6 +47,16 @@ export class SaveMessagesAndEnqueueContactCreationService {
workspaceId,
);

const isContactCreationForSentAndReceivedEmailsEnabledFeatureFlag =
await this.featureFlagRepository.findOneBy({
workspaceId: workspaceId,
key: FeatureFlagKeys.IsContactCreationForSentAndReceivedEmailsEnabled,
value: true,
});

const isContactCreationForSentAndReceivedEmailsEnabled =
isContactCreationForSentAndReceivedEmailsEnabledFeatureFlag?.value;

const participantsWithMessageId = await workspaceDataSource?.transaction(
async (transactionManager: EntityManager) => {
const messageExternalIdsAndIdsMap =
Expand All @@ -62,8 +79,9 @@ export class SaveMessagesAndEnqueueContactCreationService {
messageId,
shouldCreateContact:
messageChannel.isContactAutoCreationEnabled &&
message.participants.find((p) => p.role === 'from')
?.handle === connectedAccount.handle,
(isContactCreationForSentAndReceivedEmailsEnabled ||
message.participants.find((p) => p.role === 'from')
?.handle === connectedAccount.handle),
}))
: [];
});
Expand Down

0 comments on commit 936ac40

Please sign in to comment.