4738 add listeners on person creation and workspacemember creation to update participants (#4854)

Closes #4738

- Added the logic to unmatch a participant when the email of a person or
a workspace member is updated
This commit is contained in:
bosiraphael
2024-04-08 17:03:42 +02:00
committed by GitHub
parent 5019b5febc
commit 038b2c0efc
12 changed files with 406 additions and 79 deletions

View File

@ -1,53 +0,0 @@
import { Injectable } from '@nestjs/common';
import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface';
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
import { MessageParticipantRepository } from 'src/modules/messaging/repositories/message-participant.repository';
import { MessageParticipantObjectMetadata } from 'src/modules/messaging/standard-objects/message-participant.object-metadata';
export type MatchMessageParticipantsJobData = {
workspaceId: string;
email: string;
personId?: string;
workspaceMemberId?: string;
};
@Injectable()
export class MatchMessageParticipantJob
implements MessageQueueJob<MatchMessageParticipantsJobData>
{
constructor(
@InjectObjectMetadataRepository(MessageParticipantObjectMetadata)
private readonly messageParticipantRepository: MessageParticipantRepository,
) {}
async handle(data: MatchMessageParticipantsJobData): Promise<void> {
const { workspaceId, personId, workspaceMemberId, email } = data;
const messageParticipantsToUpdate =
await this.messageParticipantRepository.getByHandles(
[email],
workspaceId,
);
const messageParticipantIdsToUpdate = messageParticipantsToUpdate.map(
(participant) => participant.id,
);
if (personId) {
await this.messageParticipantRepository.updateParticipantsPersonId(
messageParticipantIdsToUpdate,
personId,
workspaceId,
);
}
if (workspaceMemberId) {
await this.messageParticipantRepository.updateParticipantsWorkspaceMemberId(
messageParticipantIdsToUpdate,
workspaceMemberId,
workspaceId,
);
}
}
}

View File

@ -1,60 +0,0 @@
import { Inject, Injectable } from '@nestjs/common';
import { OnEvent } from '@nestjs/event-emitter';
import { ObjectRecordCreateEvent } from 'src/engine/integrations/event-emitter/types/object-record-create.event';
import { ObjectRecordUpdateEvent } from 'src/engine/integrations/event-emitter/types/object-record-update.event';
import { objectRecordChangedProperties as objectRecordUpdateEventChangedProperties } from 'src/engine/integrations/event-emitter/utils/object-record-changed-properties.util';
import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants';
import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service';
import {
MatchMessageParticipantJob,
MatchMessageParticipantsJobData,
} from 'src/modules/messaging/jobs/match-message-participant.job';
import { PersonObjectMetadata } from 'src/modules/person/standard-objects/person.object-metadata';
@Injectable()
export class MessagingPersonListener {
constructor(
@Inject(MessageQueue.messagingQueue)
private readonly messageQueueService: MessageQueueService,
) {}
@OnEvent('person.created')
async handleCreatedEvent(
payload: ObjectRecordCreateEvent<PersonObjectMetadata>,
) {
if (payload.details.after.email === null) {
return;
}
this.messageQueueService.add<MatchMessageParticipantsJobData>(
MatchMessageParticipantJob.name,
{
workspaceId: payload.workspaceId,
email: payload.details.after.email,
personId: payload.recordId,
},
);
}
@OnEvent('person.updated')
async handleUpdatedEvent(
payload: ObjectRecordUpdateEvent<PersonObjectMetadata>,
) {
if (
objectRecordUpdateEventChangedProperties(
payload.details.before,
payload.details.after,
).includes('email')
) {
this.messageQueueService.add<MatchMessageParticipantsJobData>(
MatchMessageParticipantJob.name,
{
workspaceId: payload.workspaceId,
email: payload.details.after.email,
personId: payload.recordId,
},
);
}
}
}

View File

@ -1,60 +0,0 @@
import { Inject, Injectable } from '@nestjs/common';
import { OnEvent } from '@nestjs/event-emitter';
import { ObjectRecordCreateEvent } from 'src/engine/integrations/event-emitter/types/object-record-create.event';
import { ObjectRecordUpdateEvent } from 'src/engine/integrations/event-emitter/types/object-record-update.event';
import { objectRecordChangedProperties as objectRecordUpdateEventChangedProperties } from 'src/engine/integrations/event-emitter/utils/object-record-changed-properties.util';
import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants';
import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service';
import {
MatchMessageParticipantJob,
MatchMessageParticipantsJobData,
} from 'src/modules/messaging/jobs/match-message-participant.job';
import { WorkspaceMemberObjectMetadata } from 'src/modules/workspace-member/standard-objects/workspace-member.object-metadata';
@Injectable()
export class MessagingWorkspaceMemberListener {
constructor(
@Inject(MessageQueue.messagingQueue)
private readonly messageQueueService: MessageQueueService,
) {}
@OnEvent('workspaceMember.created')
async handleCreatedEvent(
payload: ObjectRecordCreateEvent<WorkspaceMemberObjectMetadata>,
) {
if (payload.details.after.userEmail === null) {
return;
}
await this.messageQueueService.add<MatchMessageParticipantsJobData>(
MatchMessageParticipantJob.name,
{
workspaceId: payload.workspaceId,
email: payload.details.after.userEmail,
workspaceMemberId: payload.details.after.id,
},
);
}
@OnEvent('workspaceMember.updated')
async handleUpdatedEvent(
payload: ObjectRecordUpdateEvent<WorkspaceMemberObjectMetadata>,
) {
if (
objectRecordUpdateEventChangedProperties(
payload.details.before,
payload.details.after,
).includes('userEmail')
) {
await this.messageQueueService.add<MatchMessageParticipantsJobData>(
MatchMessageParticipantJob.name,
{
workspaceId: payload.workspaceId,
email: payload.details.after.userEmail,
workspaceMemberId: payload.recordId,
},
);
}
}
}

View File

@ -1,8 +1,8 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { MessagingPersonListener } from 'src/modules/messaging/listeners/messaging-person.listener';
import { MessagingWorkspaceMemberListener } from 'src/modules/messaging/listeners/messaging-workspace-member.listener';
import { ParticipantPersonListener } from 'src/modules/connected-account/listeners/participant-person.listener';
import { ParticipantWorkspaceMemberListener } from 'src/modules/connected-account/listeners/participant-workspace-member.listener';
import { MessagingMessageChannelListener } from 'src/modules/messaging/listeners/messaging-message-channel.listener';
import { MessagingConnectedAccountListener } from 'src/modules/messaging/listeners/messaging-connected-account.listener';
import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
@ -10,8 +10,8 @@ import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-
@Module({
imports: [TypeOrmModule.forFeature([FeatureFlagEntity], 'core')],
providers: [
MessagingPersonListener,
MessagingWorkspaceMemberListener,
ParticipantPersonListener,
ParticipantWorkspaceMemberListener,
MessagingMessageChannelListener,
MessagingConnectedAccountListener,
],

View File

@ -63,6 +63,38 @@ export class MessageParticipantRepository {
);
}
public async removePersonIdByHandle(
handle: string,
workspaceId: string,
transactionManager?: EntityManager,
) {
const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId);
await this.workspaceDataSourceService.executeRawQuery(
`UPDATE ${dataSourceSchema}."messageParticipant" SET "personId" = NULL WHERE "handle" = $1`,
[handle],
workspaceId,
transactionManager,
);
}
public async removeWorkspaceMemberIdByHandle(
handle: string,
workspaceId: string,
transactionManager?: EntityManager,
) {
const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId);
await this.workspaceDataSourceService.executeRawQuery(
`UPDATE ${dataSourceSchema}."messageParticipant" SET "workspaceMemberId" = NULL WHERE "handle" = $1`,
[handle],
workspaceId,
transactionManager,
);
}
public async getByMessageChannelIdWithoutPersonIdAndWorkspaceMemberIdAndMessageOutgoing(
messageChannelId: string,
workspaceId: string,

View File

@ -4,12 +4,16 @@ import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repos
import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
import { AddPersonIdAndWorkspaceMemberIdModule } from 'src/modules/connected-account/services/add-person-id-and-workspace-member-id/add-person-id-and-workspace-member-id.module';
import { MessageParticipantService } from 'src/modules/messaging/services/message-participant/message-participant.service';
import { MessageParticipantObjectMetadata } from 'src/modules/messaging/standard-objects/message-participant.object-metadata';
import { PersonObjectMetadata } from 'src/modules/person/standard-objects/person.object-metadata';
@Module({
imports: [
WorkspaceDataSourceModule,
ObjectMetadataRepositoryModule.forFeature([PersonObjectMetadata]),
ObjectMetadataRepositoryModule.forFeature([
PersonObjectMetadata,
MessageParticipantObjectMetadata,
]),
AddPersonIdAndWorkspaceMemberIdModule,
],
providers: [MessageParticipantService],

View File

@ -12,11 +12,15 @@ import { PersonObjectMetadata } from 'src/modules/person/standard-objects/person
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
import { getFlattenedValuesAndValuesStringForBatchRawQuery } from 'src/modules/calendar/utils/getFlattenedValuesAndValuesStringForBatchRawQuery.util';
import { AddPersonIdAndWorkspaceMemberIdService } from 'src/modules/connected-account/services/add-person-id-and-workspace-member-id/add-person-id-and-workspace-member-id.service';
import { MessageParticipantRepository } from 'src/modules/messaging/repositories/message-participant.repository';
import { MessageParticipantObjectMetadata } from 'src/modules/messaging/standard-objects/message-participant.object-metadata';
@Injectable()
export class MessageParticipantService {
constructor(
private readonly workspaceDataSourceService: WorkspaceDataSourceService,
@InjectObjectMetadataRepository(MessageParticipantObjectMetadata)
private readonly messageParticipantRepository: MessageParticipantRepository,
@InjectObjectMetadataRepository(PersonObjectMetadata)
private readonly personRepository: PersonRepository,
private readonly addPersonIdAndWorkspaceMemberIdService: AddPersonIdAndWorkspaceMemberIdService,
@ -107,4 +111,56 @@ export class MessageParticipantService {
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) {
await this.messageParticipantRepository.updateParticipantsPersonId(
messageParticipantIdsToUpdate,
personId,
workspaceId,
);
}
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,
);
}
}
}