6255 move services from messaging common module into the correct module and refactor them (#6409)

Closes #6255 

- Move files from `messaging/common` into the correct module
- Remove common module between calendar and messaging
`calendar-messaging-participant-manager`
- Update and fix massaging and calendar participant matching
- Create `MatchParticipantModule`

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
bosiraphael
2024-07-27 12:29:02 +02:00
committed by GitHub
co-authored by Charles Bochet
parent 3060eb4e1e
commit d0db3b765f
42 changed files with 398 additions and 540 deletions
@@ -3,7 +3,8 @@ import { Scope } from '@nestjs/common';
import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator';
import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator';
import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants';
import { MessagingMessageParticipantService } from 'src/modules/messaging/message-participant-manager/services/messaging-message-participant.service';
import { MatchParticipantService } from 'src/modules/match-participant/match-participant.service';
import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity';
export type MessageParticipantMatchParticipantJobData = {
workspaceId: string;
@@ -18,16 +19,16 @@ export type MessageParticipantMatchParticipantJobData = {
})
export class MessageParticipantMatchParticipantJob {
constructor(
private readonly messageParticipantService: MessagingMessageParticipantService,
private readonly matchParticipantService: MatchParticipantService<MessageParticipantWorkspaceEntity>,
) {}
@Process(MessageParticipantMatchParticipantJob.name)
async handle(data: MessageParticipantMatchParticipantJobData): Promise<void> {
const { workspaceId, email, personId, workspaceMemberId } = data;
const { email, personId, workspaceMemberId } = data;
await this.messageParticipantService.matchMessageParticipants(
workspaceId,
await this.matchParticipantService.matchParticipantsAfterPersonOrWorkspaceMemberCreation(
email,
'messageParticipant',
personId,
workspaceMemberId,
);
@@ -1,9 +1,10 @@
import { Scope } from '@nestjs/common';
import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator';
import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator';
import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants';
import { MessagingMessageParticipantService } from 'src/modules/messaging/message-participant-manager/services/messaging-message-participant.service';
import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator';
import { MatchParticipantService } from 'src/modules/match-participant/match-participant.service';
import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity';
export type MessageParticipantUnmatchParticipantJobData = {
workspaceId: string;
@@ -18,18 +19,18 @@ export type MessageParticipantUnmatchParticipantJobData = {
})
export class MessageParticipantUnmatchParticipantJob {
constructor(
private readonly messageParticipantService: MessagingMessageParticipantService,
private readonly matchParticipantService: MatchParticipantService<MessageParticipantWorkspaceEntity>,
) {}
@Process(MessageParticipantUnmatchParticipantJob.name)
async handle(
data: MessageParticipantUnmatchParticipantJobData,
): Promise<void> {
const { workspaceId, email, personId, workspaceMemberId } = data;
const { email, personId, workspaceMemberId } = data;
await this.messageParticipantService.unmatchMessageParticipants(
workspaceId,
await this.matchParticipantService.unmatchParticipants(
email,
'messageParticipant',
personId,
workspaceMemberId,
);
@@ -1,9 +1,5 @@
import { Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator';
import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator';
import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants';
@@ -35,8 +31,6 @@ export class MessagingCreateCompanyAndContactAfterSyncJob {
private readonly messageChannelService: MessageChannelRepository,
@InjectObjectMetadataRepository(MessageParticipantWorkspaceEntity)
private readonly messageParticipantRepository: MessageParticipantRepository,
@InjectRepository(FeatureFlagEntity, 'core')
private readonly featureFlagRepository: Repository<FeatureFlagEntity>,
@InjectObjectMetadataRepository(ConnectedAccountWorkspaceEntity)
private readonly connectedAccountRepository: ConnectedAccountRepository,
) {}
@@ -7,9 +7,9 @@ import { Repository } from 'typeorm';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity';
import { TimelineActivityRepository } from 'src/modules/timeline/repositiories/timeline-activity.repository';
import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity';
import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity';
@Injectable()
export class MessageParticipantListener {
@@ -25,9 +25,9 @@ export class MessageParticipantListener {
public async handleMessageParticipantMatched(payload: {
workspaceId: string;
workspaceMemberId: string;
messageParticipants: MessageParticipantWorkspaceEntity[];
participants: MessageParticipantWorkspaceEntity[];
}): Promise<void> {
const messageParticipants = payload.messageParticipants ?? [];
const messageParticipants = payload.participants ?? [];
// TODO: move to a job?
@@ -7,9 +7,9 @@ import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadat
import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module';
import { TwentyORMModule } from 'src/engine/twenty-orm/twenty-orm.module';
import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
import { AddPersonIdAndWorkspaceMemberIdService } from 'src/modules/calendar-messaging-participant-manager/services/add-person-id-and-workspace-member-id/add-person-id-and-workspace-member-id.service';
import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity';
import { ContactCreationManagerModule } from 'src/modules/contact-creation-manager/contact-creation-manager.module';
import { MatchParticipantModule } from 'src/modules/match-participant/match-participant.module';
import { MessagingCommonModule } from 'src/modules/messaging/common/messaging-common.module';
import { MessageParticipantMatchParticipantJob } from 'src/modules/messaging/message-participant-manager/jobs/message-participant-match-participant.job';
import { MessageParticipantUnmatchParticipantJob } from 'src/modules/messaging/message-participant-manager/jobs/message-participant-unmatch-participant.job';
@@ -32,6 +32,7 @@ import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-o
TypeOrmModule.forFeature([ObjectMetadataEntity], 'metadata'),
TwentyORMModule.forFeature([CalendarChannelWorkspaceEntity]),
MessagingCommonModule,
MatchParticipantModule,
],
providers: [
MessagingMessageParticipantService,
@@ -41,7 +42,6 @@ import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-o
MessageParticipantListener,
MessageParticipantPersonListener,
MessageParticipantWorkspaceMemberListener,
AddPersonIdAndWorkspaceMemberIdService,
],
exports: [MessagingMessageParticipantService],
})
@@ -1,181 +1,45 @@
import { Injectable } from '@nestjs/common';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { EntityManager } from 'typeorm';
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
import { PersonRepository } from 'src/modules/person/repositories/person.repository';
import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity';
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
import { getFlattenedValuesAndValuesStringForBatchRawQuery } from 'src/modules/calendar/calendar-event-import-manager/utils/get-flattened-values-and-values-string-for-batch-raw-query.util';
import { AddPersonIdAndWorkspaceMemberIdService } from 'src/modules/calendar-messaging-participant-manager/services/add-person-id-and-workspace-member-id/add-person-id-and-workspace-member-id.service';
import { MessageParticipantRepository } from 'src/modules/messaging/common/repositories/message-participant.repository';
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
import { MatchParticipantService } from 'src/modules/match-participant/match-participant.service';
import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity';
import { ParticipantWithMessageId } from 'src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-message';
@Injectable()
export class MessagingMessageParticipantService {
constructor(
private readonly workspaceDataSourceService: WorkspaceDataSourceService,
@InjectObjectMetadataRepository(MessageParticipantWorkspaceEntity)
private readonly messageParticipantRepository: MessageParticipantRepository,
@InjectObjectMetadataRepository(PersonWorkspaceEntity)
private readonly personRepository: PersonRepository,
private readonly addPersonIdAndWorkspaceMemberIdService: AddPersonIdAndWorkspaceMemberIdService,
private readonly eventEmitter: EventEmitter2,
private readonly twentyORMManager: TwentyORMManager,
private readonly matchParticipantService: MatchParticipantService<MessageParticipantWorkspaceEntity>,
) {}
public async updateMessageParticipantsAfterPeopleCreation(
createdPeople: PersonWorkspaceEntity[],
workspaceId: string,
transactionManager?: EntityManager,
): Promise<MessageParticipantWorkspaceEntity[]> {
const participants = await this.messageParticipantRepository.getByHandles(
createdPeople.map((person) => person.email),
workspaceId,
transactionManager,
);
if (!participants) return [];
const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId);
const handles = participants.map((participant) => participant.handle);
const participantPersonIds = await this.personRepository.getByEmails(
handles,
workspaceId,
transactionManager,
);
const messageParticipantsToUpdate = participants.map((participant) => ({
id: participant.id,
personId: participantPersonIds.find(
(e: { id: string; email: string }) => e.email === participant.handle,
)?.id,
}));
if (messageParticipantsToUpdate.length === 0) return [];
const { flattenedValues, valuesString } =
getFlattenedValuesAndValuesStringForBatchRawQuery(
messageParticipantsToUpdate,
{
id: 'uuid',
personId: 'uuid',
},
);
return (
await this.workspaceDataSourceService.executeRawQuery(
`UPDATE ${dataSourceSchema}."messageParticipant" AS "messageParticipant" SET "personId" = "data"."personId"
FROM (VALUES ${valuesString}) AS "data"("id", "personId")
WHERE "messageParticipant"."id" = "data"."id"
RETURNING *`,
flattenedValues,
workspaceId,
transactionManager,
)
).flat();
}
public async saveMessageParticipants(
participants: ParticipantWithMessageId[],
workspaceId: string,
transactionManager?: EntityManager,
): Promise<MessageParticipantWorkspaceEntity[]> {
if (!participants) return [];
const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId);
const messageParticipantsToSave =
await this.addPersonIdAndWorkspaceMemberIdService.addPersonIdAndWorkspaceMemberId(
participants,
workspaceId,
transactionManager,
): Promise<void> {
const messageParticipantRepository =
await this.twentyORMManager.getRepository<MessageParticipantWorkspaceEntity>(
'messageParticipant',
);
const { flattenedValues, valuesString } =
getFlattenedValuesAndValuesStringForBatchRawQuery(
messageParticipantsToSave,
{
messageId: 'uuid',
role: `${dataSourceSchema}."messageParticipant_role_enum"`,
handle: 'text',
displayName: 'text',
personId: 'uuid',
workspaceMemberId: 'uuid',
},
);
const savedParticipants = await messageParticipantRepository.save(
participants.map((participant) => {
return {
messageId: participant.messageId,
role: participant.role,
handle: participant.handle,
displayName: participant.displayName,
};
}),
{},
transactionManager,
);
if (messageParticipantsToSave.length === 0) return [];
return await this.workspaceDataSourceService.executeRawQuery(
`INSERT INTO ${dataSourceSchema}."messageParticipant" ("messageId", "role", "handle", "displayName", "personId", "workspaceMemberId") VALUES ${valuesString} RETURNING *`,
flattenedValues,
workspaceId,
await this.matchParticipantService.matchParticipants(
savedParticipants,
'messageParticipant',
transactionManager,
);
}
public async matchMessageParticipants(
workspaceId: string,
email: string,
personId?: string,
workspaceMemberId?: string,
) {
const messageParticipantsToUpdate =
await this.messageParticipantRepository.getByHandles(
[email],
workspaceId,
);
const messageParticipantIdsToUpdate = messageParticipantsToUpdate.map(
(participant) => participant.id,
);
if (personId) {
const updatedMessageParticipants =
await this.messageParticipantRepository.updateParticipantsPersonIdAndReturn(
messageParticipantIdsToUpdate,
personId,
workspaceId,
);
this.eventEmitter.emit(`messageParticipant.matched`, {
workspaceId,
workspaceMemberId: null,
messageParticipants: updatedMessageParticipants,
});
}
if (workspaceMemberId) {
await this.messageParticipantRepository.updateParticipantsWorkspaceMemberId(
messageParticipantIdsToUpdate,
workspaceMemberId,
workspaceId,
);
}
}
public async unmatchMessageParticipants(
workspaceId: string,
handle: string,
personId?: string,
workspaceMemberId?: string,
) {
if (personId) {
await this.messageParticipantRepository.removePersonIdByHandle(
handle,
workspaceId,
);
}
if (workspaceMemberId) {
await this.messageParticipantRepository.removeWorkspaceMemberIdByHandle(
handle,
workspaceId,
);
}
}
}