[messaging] Add messageParticipant matching once people emails are updated (#3887)
* poc nest event emitter * add match message participant listener * add workspacemember listener * fix after review * fix deep-equal
This commit is contained in:
@ -0,0 +1,47 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { MessageQueueJob } from 'src/integrations/message-queue/interfaces/message-queue-job.interface';
|
||||
|
||||
import { MessageParticipantService } from 'src/workspace/messaging/message-participant/message-participant.service';
|
||||
|
||||
export type MatchMessageParticipantsJobData = {
|
||||
workspaceId: string;
|
||||
email: string;
|
||||
personId?: string;
|
||||
workspaceMemberId?: string;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class MatchMessageParticipantJob
|
||||
implements MessageQueueJob<MatchMessageParticipantsJobData>
|
||||
{
|
||||
constructor(
|
||||
private readonly messageParticipantService: MessageParticipantService,
|
||||
) {}
|
||||
|
||||
async handle(data: MatchMessageParticipantsJobData): Promise<void> {
|
||||
const { workspaceId, personId, workspaceMemberId, email } = data;
|
||||
|
||||
const messageParticipantsToUpdate =
|
||||
await this.messageParticipantService.getByHandles([email], workspaceId);
|
||||
|
||||
const messageParticipantIdsToUpdate = messageParticipantsToUpdate.map(
|
||||
(participant) => participant.id,
|
||||
);
|
||||
|
||||
if (personId) {
|
||||
await this.messageParticipantService.updateParticipantsPersonId(
|
||||
messageParticipantIdsToUpdate,
|
||||
personId,
|
||||
workspaceId,
|
||||
);
|
||||
}
|
||||
if (workspaceMemberId) {
|
||||
await this.messageParticipantService.updateParticipantsWorkspaceMemberId(
|
||||
messageParticipantIdsToUpdate,
|
||||
workspaceMemberId,
|
||||
workspaceId,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { OnEvent } from '@nestjs/event-emitter';
|
||||
|
||||
import { ObjectRecordCreateEvent } from 'src/integrations/event-emitter/types/object-record-create.event';
|
||||
import { ObjectRecordUpdateEvent } from 'src/integrations/event-emitter/types/object-record-update.event';
|
||||
import { objectRecordChangedProperties as objectRecordUpdateEventChangedProperties } from 'src/integrations/event-emitter/utils/object-record-changed-properties.util';
|
||||
import { MessageQueue } from 'src/integrations/message-queue/message-queue.constants';
|
||||
import { MessageQueueService } from 'src/integrations/message-queue/services/message-queue.service';
|
||||
import {
|
||||
MatchMessageParticipantJob,
|
||||
MatchMessageParticipantsJobData,
|
||||
} from 'src/workspace/messaging/jobs/match-message-participant.job';
|
||||
import { PersonObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/person.object-metadata';
|
||||
|
||||
@Injectable()
|
||||
export class MessagingPersonListener {
|
||||
constructor(
|
||||
@Inject(MessageQueue.messagingQueue)
|
||||
private readonly messageQueueService: MessageQueueService,
|
||||
) {}
|
||||
|
||||
@OnEvent('person.created')
|
||||
handleCreatedEvent(payload: ObjectRecordCreateEvent<PersonObjectMetadata>) {
|
||||
if (payload.createdRecord.email === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.messageQueueService.add<MatchMessageParticipantsJobData>(
|
||||
MatchMessageParticipantJob.name,
|
||||
{
|
||||
workspaceId: payload.workspaceId,
|
||||
email: payload.createdRecord.email,
|
||||
personId: payload.createdRecord.id,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@OnEvent('person.updated')
|
||||
handleUpdatedEvent(payload: ObjectRecordUpdateEvent<PersonObjectMetadata>) {
|
||||
console.log(
|
||||
objectRecordUpdateEventChangedProperties(
|
||||
payload.previousRecord,
|
||||
payload.updatedRecord,
|
||||
),
|
||||
);
|
||||
|
||||
if (
|
||||
objectRecordUpdateEventChangedProperties(
|
||||
payload.previousRecord,
|
||||
payload.updatedRecord,
|
||||
).includes('email')
|
||||
) {
|
||||
this.messageQueueService.add<MatchMessageParticipantsJobData>(
|
||||
MatchMessageParticipantJob.name,
|
||||
{
|
||||
workspaceId: payload.workspaceId,
|
||||
email: payload.updatedRecord.email,
|
||||
personId: payload.updatedRecord.id,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { OnEvent } from '@nestjs/event-emitter';
|
||||
|
||||
import { ObjectRecordCreateEvent } from 'src/integrations/event-emitter/types/object-record-create.event';
|
||||
import { ObjectRecordUpdateEvent } from 'src/integrations/event-emitter/types/object-record-update.event';
|
||||
import { objectRecordChangedProperties as objectRecordUpdateEventChangedProperties } from 'src/integrations/event-emitter/utils/object-record-changed-properties.util';
|
||||
import { MessageQueue } from 'src/integrations/message-queue/message-queue.constants';
|
||||
import { MessageQueueService } from 'src/integrations/message-queue/services/message-queue.service';
|
||||
import {
|
||||
MatchMessageParticipantJob,
|
||||
MatchMessageParticipantsJobData,
|
||||
} from 'src/workspace/messaging/jobs/match-message-participant.job';
|
||||
import { WorkspaceMemberObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/workspace-member.object-metadata';
|
||||
|
||||
@Injectable()
|
||||
export class MessagingWorkspaceMemberListener {
|
||||
constructor(
|
||||
@Inject(MessageQueue.messagingQueue)
|
||||
private readonly messageQueueService: MessageQueueService,
|
||||
) {}
|
||||
|
||||
@OnEvent('workspaceMember.created')
|
||||
handleCreatedEvent(
|
||||
payload: ObjectRecordCreateEvent<WorkspaceMemberObjectMetadata>,
|
||||
) {
|
||||
if (payload.createdRecord.userEmail === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.messageQueueService.add<MatchMessageParticipantsJobData>(
|
||||
MatchMessageParticipantJob.name,
|
||||
{
|
||||
workspaceId: payload.workspaceId,
|
||||
email: payload.createdRecord.userEmail,
|
||||
workspaceMemberId: payload.createdRecord.id,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@OnEvent('workspaceMember.updated')
|
||||
handleUpdatedEvent(
|
||||
payload: ObjectRecordUpdateEvent<WorkspaceMemberObjectMetadata>,
|
||||
) {
|
||||
if (
|
||||
objectRecordUpdateEventChangedProperties(
|
||||
payload.previousRecord,
|
||||
payload.updatedRecord,
|
||||
).includes('userEmail')
|
||||
) {
|
||||
this.messageQueueService.add<MatchMessageParticipantsJobData>(
|
||||
MatchMessageParticipantJob.name,
|
||||
{
|
||||
workspaceId: payload.workspaceId,
|
||||
email: payload.updatedRecord.userEmail,
|
||||
workspaceMemberId: payload.updatedRecord.id,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { MessageParticipantService } from 'src/workspace/messaging/message-participant/message-participant.service';
|
||||
import { WorkspaceDataSourceModule } from 'src/workspace/workspace-datasource/workspace-datasource.module';
|
||||
|
||||
@Module({
|
||||
imports: [WorkspaceDataSourceModule],
|
||||
providers: [MessageParticipantService],
|
||||
exports: [MessageParticipantService],
|
||||
})
|
||||
export class MessageParticipantModule {}
|
||||
@ -0,0 +1,64 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { EntityManager } from 'typeorm';
|
||||
|
||||
import { WorkspaceDataSourceService } from 'src/workspace/workspace-datasource/workspace-datasource.service';
|
||||
import { MessageParticipantObjectMetadata } from 'src/workspace/workspace-sync-metadata/standard-objects/message-participant.object-metadata';
|
||||
import { ObjectRecord } from 'src/workspace/workspace-sync-metadata/types/object-record';
|
||||
|
||||
@Injectable()
|
||||
export class MessageParticipantService {
|
||||
constructor(
|
||||
private readonly workspaceDataSourceService: WorkspaceDataSourceService,
|
||||
) {}
|
||||
|
||||
public async getByHandles(
|
||||
handles: string[],
|
||||
workspaceId: string,
|
||||
transactionManager?: EntityManager,
|
||||
): Promise<ObjectRecord<MessageParticipantObjectMetadata>[]> {
|
||||
const dataSourceSchema =
|
||||
this.workspaceDataSourceService.getSchemaName(workspaceId);
|
||||
|
||||
return await this.workspaceDataSourceService.executeRawQuery(
|
||||
`SELECT * FROM ${dataSourceSchema}."messageParticipant" WHERE "handle" = ANY($1)`,
|
||||
[handles],
|
||||
workspaceId,
|
||||
transactionManager,
|
||||
);
|
||||
}
|
||||
|
||||
public async updateParticipantsPersonId(
|
||||
participantIds: string[],
|
||||
personId: string,
|
||||
workspaceId: string,
|
||||
transactionManager?: EntityManager,
|
||||
) {
|
||||
const dataSourceSchema =
|
||||
this.workspaceDataSourceService.getSchemaName(workspaceId);
|
||||
|
||||
await this.workspaceDataSourceService.executeRawQuery(
|
||||
`UPDATE ${dataSourceSchema}."messageParticipant" SET "personId" = $1 WHERE "id" = ANY($2)`,
|
||||
[personId, participantIds],
|
||||
workspaceId,
|
||||
transactionManager,
|
||||
);
|
||||
}
|
||||
|
||||
public async updateParticipantsWorkspaceMemberId(
|
||||
participantIds: string[],
|
||||
workspaceMemberId: string,
|
||||
workspaceId: string,
|
||||
transactionManager?: EntityManager,
|
||||
) {
|
||||
const dataSourceSchema =
|
||||
this.workspaceDataSourceService.getSchemaName(workspaceId);
|
||||
|
||||
await this.workspaceDataSourceService.executeRawQuery(
|
||||
`UPDATE ${dataSourceSchema}."messageParticipant" SET "workspaceMemberId" = $1 WHERE "id" = ANY($2)`,
|
||||
[workspaceMemberId, participantIds],
|
||||
workspaceId,
|
||||
transactionManager,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,18 +1,21 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { EnvironmentModule } from 'src/integrations/environment/environment.module';
|
||||
import { ConnectedAccountModule } from 'src/workspace/messaging/connected-account/connected-account.module';
|
||||
import { MessageChannelMessageAssociationModule } from 'src/workspace/messaging/message-channel-message-association/message-channel-message-assocation.module';
|
||||
import { MessageChannelModule } from 'src/workspace/messaging/message-channel/message-channel.module';
|
||||
import { MessageThreadModule } from 'src/workspace/messaging/message-thread/message-thread.module';
|
||||
import { MessagingUtilsService } from 'src/workspace/messaging/services/messaging-utils.service';
|
||||
import { EnvironmentModule } from 'src/integrations/environment/environment.module';
|
||||
import { MessagingPersonListener } from 'src/workspace/messaging/listeners/messaging-person.listener';
|
||||
import { MessageModule } from 'src/workspace/messaging/message/message.module';
|
||||
import { GmailClientProvider } from 'src/workspace/messaging/providers/gmail/gmail-client.provider';
|
||||
import { FetchMessagesByBatchesService } from 'src/workspace/messaging/services/fetch-messages-by-batches.service';
|
||||
import { GmailFullSyncService } from 'src/workspace/messaging/services/gmail-full-sync.service';
|
||||
import { GmailPartialSyncService } from 'src/workspace/messaging/services/gmail-partial-sync.service';
|
||||
import { GmailRefreshAccessTokenService } from 'src/workspace/messaging/services/gmail-refresh-access-token.service';
|
||||
import { MessagingUtilsService } from 'src/workspace/messaging/services/messaging-utils.service';
|
||||
import { WorkspaceDataSourceModule } from 'src/workspace/workspace-datasource/workspace-datasource.module';
|
||||
import { MessageParticipantModule } from 'src/workspace/messaging/message-participant/message-participant.module';
|
||||
import { MessagingWorkspaceMemberListener } from 'src/workspace/messaging/listeners/messaging-workspace-member.listener';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@ -23,6 +26,7 @@ import { WorkspaceDataSourceModule } from 'src/workspace/workspace-datasource/wo
|
||||
MessageChannelMessageAssociationModule,
|
||||
MessageModule,
|
||||
MessageThreadModule,
|
||||
MessageParticipantModule,
|
||||
],
|
||||
providers: [
|
||||
GmailFullSyncService,
|
||||
@ -31,6 +35,8 @@ import { WorkspaceDataSourceModule } from 'src/workspace/workspace-datasource/wo
|
||||
GmailRefreshAccessTokenService,
|
||||
MessagingUtilsService,
|
||||
GmailClientProvider,
|
||||
MessagingPersonListener,
|
||||
MessagingWorkspaceMemberListener,
|
||||
],
|
||||
exports: [
|
||||
GmailPartialSyncService,
|
||||
@ -39,4 +45,4 @@ import { WorkspaceDataSourceModule } from 'src/workspace/workspace-datasource/wo
|
||||
MessagingUtilsService,
|
||||
],
|
||||
})
|
||||
export class FetchWorkspaceMessagesModule {}
|
||||
export class MessagingModule {}
|
||||
@ -4,7 +4,6 @@ import { gmail_v1 } from 'googleapis';
|
||||
|
||||
import { FetchMessagesByBatchesService } from 'src/workspace/messaging/services/fetch-messages-by-batches.service';
|
||||
import { GmailClientProvider } from 'src/workspace/messaging/providers/gmail/gmail-client.provider';
|
||||
import { MessagingUtilsService } from 'src/workspace/messaging/services/messaging-utils.service';
|
||||
import { MessageQueueService } from 'src/integrations/message-queue/services/message-queue.service';
|
||||
import { MessageQueue } from 'src/integrations/message-queue/message-queue.constants';
|
||||
import {
|
||||
@ -12,8 +11,9 @@ import {
|
||||
GmailFullSyncJobData,
|
||||
} from 'src/workspace/messaging/jobs/gmail-full-sync.job';
|
||||
import { ConnectedAccountService } from 'src/workspace/messaging/connected-account/connected-account.service';
|
||||
import { MessageChannelService } from 'src/workspace/messaging/message-channel/message-channel.service';
|
||||
import { WorkspaceDataSourceService } from 'src/workspace/workspace-datasource/workspace-datasource.service';
|
||||
import { MessageChannelService } from 'src/workspace/messaging/message-channel/message-channel.service';
|
||||
import { MessagingUtilsService } from 'src/workspace/messaging/services/messaging-utils.service';
|
||||
|
||||
@Injectable()
|
||||
export class GmailPartialSyncService {
|
||||
|
||||
Reference in New Issue
Block a user