4745 move common logic between messaging and calendar in packagestwenty serversrcmodulesconnected account (#4962)

Closes #4745
This commit is contained in:
bosiraphael
2024-04-15 18:10:12 +02:00
committed by GitHub
parent d7d9f0c16b
commit 691454ef3b
20 changed files with 27 additions and 19 deletions

View File

@ -5,7 +5,7 @@ import { v4 } from 'uuid';
import axios, { AxiosInstance } from 'axios';
import { CompanyRepository } from 'src/modules/company/repositories/company.repository';
import { getCompanyNameFromDomainName } from 'src/modules/messaging/utils/get-company-name-from-domain-name.util';
import { getCompanyNameFromDomainName } from 'src/modules/calendar-messaging-participant/utils/get-company-name-from-domain-name.util';
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
import { CompanyObjectMetadata } from 'src/modules/company/standard-objects/company.object-metadata';
@Injectable()

View File

@ -4,7 +4,7 @@ import { EntityManager } from 'typeorm';
import { v4 } from 'uuid';
import { PersonRepository } from 'src/modules/person/repositories/person.repository';
import { getFirstNameAndLastNameFromHandleAndDisplayName } from 'src/modules/messaging/utils/get-first-name-and-last-name-from-handle-and-display-name.util';
import { getFirstNameAndLastNameFromHandleAndDisplayName } from 'src/modules/calendar-messaging-participant/utils/get-first-name-and-last-name-from-handle-and-display-name.util';
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
import { PersonObjectMetadata } from 'src/modules/person/standard-objects/person.object-metadata';

View File

@ -4,7 +4,7 @@ import { InjectRepository } from '@nestjs/typeorm';
import { EntityManager, Repository } from 'typeorm';
import compact from 'lodash/compact';
import { getDomainNameFromHandle } from 'src/modules/messaging/utils/get-domain-name-from-handle.util';
import { getDomainNameFromHandle } from 'src/modules/calendar-messaging-participant/utils/get-domain-name-from-handle.util';
import { CreateCompanyService } from 'src/modules/connected-account/auto-companies-and-contacts-creation/create-company/create-company.service';
import { CreateContactService } from 'src/modules/connected-account/auto-companies-and-contacts-creation/create-contact/create-contact.service';
import { PersonRepository } from 'src/modules/person/repositories/person.repository';

View File

@ -1,4 +1,4 @@
import { getDomainNameFromHandle } from 'src/modules/messaging/utils/get-domain-name-from-handle.util';
import { getDomainNameFromHandle } from 'src/modules/calendar-messaging-participant/utils/get-domain-name-from-handle.util';
import { WorkspaceMemberObjectMetadata } from 'src/modules/workspace-member/standard-objects/workspace-member.object-metadata';
import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record';
import { Contacts } from 'src/modules/connected-account/auto-companies-and-contacts-creation/types/contact.type';

View File

@ -1,60 +0,0 @@
import { Injectable } 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 { CalendarEventParticipantService } from 'src/modules/calendar/services/calendar-event-participant/calendar-event-participant.service';
import { MessageParticipantService } from 'src/modules/messaging/services/message-participant/message-participant.service';
export type MatchParticipantJobData = {
workspaceId: string;
email: string;
personId?: string;
workspaceMemberId?: string;
};
@Injectable()
export class MatchParticipantJob
implements MessageQueueJob<MatchParticipantJobData>
{
constructor(
private readonly messageParticipantService: MessageParticipantService,
private readonly calendarEventParticipantService: CalendarEventParticipantService,
@InjectRepository(FeatureFlagEntity, 'core')
private readonly featureFlagRepository: Repository<FeatureFlagEntity>,
) {}
async handle(data: MatchParticipantJobData): Promise<void> {
const { workspaceId, email, personId, workspaceMemberId } = data;
await this.messageParticipantService.matchMessageParticipants(
workspaceId,
email,
personId,
workspaceMemberId,
);
const isCalendarEnabled = await this.featureFlagRepository.findOneBy({
workspaceId,
key: FeatureFlagKeys.IsCalendarEnabled,
value: true,
});
if (!isCalendarEnabled || !isCalendarEnabled.value) {
return;
}
await this.calendarEventParticipantService.matchCalendarEventParticipants(
workspaceId,
email,
personId,
workspaceMemberId,
);
}
}

View File

@ -1,60 +0,0 @@
import { Injectable } 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 { CalendarEventParticipantService } from 'src/modules/calendar/services/calendar-event-participant/calendar-event-participant.service';
import { MessageParticipantService } from 'src/modules/messaging/services/message-participant/message-participant.service';
export type UnmatchParticipantJobData = {
workspaceId: string;
email: string;
personId?: string;
workspaceMemberId?: string;
};
@Injectable()
export class UnmatchParticipantJob
implements MessageQueueJob<UnmatchParticipantJobData>
{
constructor(
private readonly messageParticipantService: MessageParticipantService,
private readonly calendarEventParticipantService: CalendarEventParticipantService,
@InjectRepository(FeatureFlagEntity, 'core')
private readonly featureFlagRepository: Repository<FeatureFlagEntity>,
) {}
async handle(data: UnmatchParticipantJobData): Promise<void> {
const { workspaceId, email, personId, workspaceMemberId } = data;
await this.messageParticipantService.unmatchMessageParticipants(
workspaceId,
email,
personId,
workspaceMemberId,
);
const isCalendarEnabled = await this.featureFlagRepository.findOneBy({
workspaceId,
key: FeatureFlagKeys.IsCalendarEnabled,
value: true,
});
if (!isCalendarEnabled || !isCalendarEnabled.value) {
return;
}
await this.calendarEventParticipantService.unmatchCalendarEventParticipants(
workspaceId,
email,
personId,
workspaceMemberId,
);
}
}

View File

@ -1,73 +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 {
MatchParticipantJob,
MatchParticipantJobData,
} from 'src/modules/connected-account/jobs/match-participant.job';
import {
UnmatchParticipantJobData,
UnmatchParticipantJob,
} from 'src/modules/connected-account/jobs/unmatch-participant.job';
import { PersonObjectMetadata } from 'src/modules/person/standard-objects/person.object-metadata';
@Injectable()
export class ParticipantPersonListener {
constructor(
@Inject(MessageQueue.messagingQueue)
private readonly messageQueueService: MessageQueueService,
) {}
@OnEvent('person.created')
async handleCreatedEvent(
payload: ObjectRecordCreateEvent<PersonObjectMetadata>,
) {
if (payload.details.after.email === null) {
return;
}
await this.messageQueueService.add<MatchParticipantJobData>(
MatchParticipantJob.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')
) {
await this.messageQueueService.add<UnmatchParticipantJobData>(
UnmatchParticipantJob.name,
{
workspaceId: payload.workspaceId,
email: payload.details.before.email,
personId: payload.recordId,
},
);
await this.messageQueueService.add<MatchParticipantJobData>(
MatchParticipantJob.name,
{
workspaceId: payload.workspaceId,
email: payload.details.after.email,
personId: payload.recordId,
},
);
}
}
}

View File

@ -1,73 +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 {
MatchParticipantJob,
MatchParticipantJobData,
} from 'src/modules/connected-account/jobs/match-participant.job';
import {
UnmatchParticipantJobData,
UnmatchParticipantJob,
} from 'src/modules/connected-account/jobs/unmatch-participant.job';
import { WorkspaceMemberObjectMetadata } from 'src/modules/workspace-member/standard-objects/workspace-member.object-metadata';
@Injectable()
export class ParticipantWorkspaceMemberListener {
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<MatchParticipantJobData>(
MatchParticipantJob.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<UnmatchParticipantJobData>(
UnmatchParticipantJob.name,
{
workspaceId: payload.workspaceId,
email: payload.details.before.userEmail,
personId: payload.recordId,
},
);
await this.messageQueueService.add<MatchParticipantJobData>(
MatchParticipantJob.name,
{
workspaceId: payload.workspaceId,
email: payload.details.after.userEmail,
workspaceMemberId: payload.recordId,
},
);
}
}
}

View File

@ -1,16 +0,0 @@
import { Module } from '@nestjs/common';
import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module';
import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
import { AddPersonIdAndWorkspaceMemberIdService } from 'src/modules/connected-account/services/add-person-id-and-workspace-member-id/add-person-id-and-workspace-member-id.service';
import { PersonObjectMetadata } from 'src/modules/person/standard-objects/person.object-metadata';
@Module({
imports: [
WorkspaceDataSourceModule,
ObjectMetadataRepositoryModule.forFeature([PersonObjectMetadata]),
],
providers: [AddPersonIdAndWorkspaceMemberIdService],
exports: [AddPersonIdAndWorkspaceMemberIdService],
})
export class AddPersonIdAndWorkspaceMemberIdModule {}

View File

@ -1,90 +0,0 @@
import { Injectable } from '@nestjs/common';
import { EntityManager } from 'typeorm';
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
import { PersonRepository } from 'src/modules/person/repositories/person.repository';
import { PersonObjectMetadata } from 'src/modules/person/standard-objects/person.object-metadata';
@Injectable()
export class AddPersonIdAndWorkspaceMemberIdService {
constructor(
private readonly workspaceDataSourceService: WorkspaceDataSourceService,
@InjectObjectMetadataRepository(PersonObjectMetadata)
private readonly personRepository: PersonRepository,
) {}
private async getEmailPersonIdMap(
handles: string[],
workspaceId: string,
transactionManager?: EntityManager,
): Promise<Map<string, string>> {
const personIds = await this.personRepository.getByEmails(
handles,
workspaceId,
transactionManager,
);
return new Map(personIds.map((person) => [person.email, person.id]));
}
private async getEmailWorkspaceMemberIdMap(
handles: string[],
workspaceId: string,
transactionManager?: EntityManager,
): Promise<Map<string, string>> {
const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId);
const workspaceMemberIds: {
id: string;
email: string;
}[] = await this.workspaceDataSourceService.executeRawQuery(
`SELECT "workspaceMember"."id", "connectedAccount"."handle" AS email FROM ${dataSourceSchema}."workspaceMember"
JOIN ${dataSourceSchema}."connectedAccount" ON ${dataSourceSchema}."workspaceMember"."id" = ${dataSourceSchema}."connectedAccount"."accountOwnerId"
WHERE ${dataSourceSchema}."connectedAccount"."handle" = ANY($1)`,
[handles],
workspaceId,
transactionManager,
);
return new Map(
workspaceMemberIds.map((workspaceMember) => [
workspaceMember.email,
workspaceMember.id,
]),
);
}
public async addPersonIdAndWorkspaceMemberId<T extends { handle: string }>(
objects: T[],
workspaceId: string,
transactionManager?: EntityManager,
): Promise<
(T & {
personId: string | null;
workspaceMemberId: string | null;
})[]
> {
const handles = objects.map((object) => object.handle);
const personIdMap = await this.getEmailPersonIdMap(
handles,
workspaceId,
transactionManager,
);
const workspaceMemberIdMap = await this.getEmailWorkspaceMemberIdMap(
handles,
workspaceId,
transactionManager,
);
return objects.map((object) => ({
...object,
personId: personIdMap.get(object.handle) || null,
workspaceMemberId: workspaceMemberIdMap.get(object.handle) || null,
}));
}
}