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:
@ -1,4 +1,4 @@
|
||||
import { isEmailBlocklisted } from 'src/modules/calendar-messaging-participant-manager/utils/is-email-blocklisted.util';
|
||||
import { isEmailBlocklisted } from 'src/modules/blocklist/utils/is-email-blocklisted.util';
|
||||
|
||||
describe('isEmailBlocklisted', () => {
|
||||
it('should return true if email is blocklisted', () => {
|
||||
@ -1,92 +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 { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity';
|
||||
|
||||
// TODO: Move inside person module and workspace-member module
|
||||
|
||||
@Injectable()
|
||||
export class AddPersonIdAndWorkspaceMemberIdService {
|
||||
constructor(
|
||||
private readonly workspaceDataSourceService: WorkspaceDataSourceService,
|
||||
@InjectObjectMetadataRepository(PersonWorkspaceEntity)
|
||||
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,
|
||||
}));
|
||||
}
|
||||
}
|
||||
@ -19,7 +19,6 @@ import { CalendarEventsImportService } from 'src/modules/calendar/calendar-event
|
||||
import { CalendarGetCalendarEventsService } from 'src/modules/calendar/calendar-event-import-manager/services/calendar-get-events.service';
|
||||
import { CalendarSaveEventsService } from 'src/modules/calendar/calendar-event-import-manager/services/calendar-save-events.service';
|
||||
import { CalendarEventParticipantManagerModule } from 'src/modules/calendar/calendar-event-participant-manager/calendar-event-participant-manager.module';
|
||||
import { CalendarCommonModule } from 'src/modules/calendar/common/calendar-common.module';
|
||||
import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel-event-association.workspace-entity';
|
||||
import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity';
|
||||
import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity';
|
||||
@ -51,7 +50,6 @@ import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/sta
|
||||
GoogleCalendarDriverModule,
|
||||
BillingModule,
|
||||
RefreshAccessTokenManagerModule,
|
||||
CalendarCommonModule,
|
||||
CalendarEventParticipantManagerModule,
|
||||
],
|
||||
providers: [
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { isEmailBlocklisted } from 'src/modules/calendar-messaging-participant-manager/utils/is-email-blocklisted.util';
|
||||
import { isEmailBlocklisted } from 'src/modules/blocklist/utils/is-email-blocklisted.util';
|
||||
import { CalendarEventWithParticipants } from 'src/modules/calendar/common/types/calendar-event';
|
||||
|
||||
export const filterOutBlocklistedEvents = (
|
||||
|
||||
@ -7,7 +7,6 @@ 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 { CalendarCreateCompanyAndContactAfterSyncJob } from 'src/modules/calendar/calendar-event-participant-manager/jobs/calendar-create-company-and-contact-after-sync.job';
|
||||
import { CalendarEventParticipantMatchParticipantJob } from 'src/modules/calendar/calendar-event-participant-manager/jobs/calendar-event-participant-match-participant.job';
|
||||
import { CalendarEventParticipantUnmatchParticipantJob } from 'src/modules/calendar/calendar-event-participant-manager/jobs/calendar-event-participant-unmatch-participant.job';
|
||||
@ -15,9 +14,9 @@ import { CalendarEventParticipantPersonListener } from 'src/modules/calendar/cal
|
||||
import { CalendarEventParticipantWorkspaceMemberListener } from 'src/modules/calendar/calendar-event-participant-manager/listeners/calendar-event-participant-workspace-member.listener';
|
||||
import { CalendarEventParticipantListener } from 'src/modules/calendar/calendar-event-participant-manager/listeners/calendar-event-participant.listener';
|
||||
import { CalendarEventParticipantService } from 'src/modules/calendar/calendar-event-participant-manager/services/calendar-event-participant.service';
|
||||
import { CalendarCommonModule } from 'src/modules/calendar/common/calendar-common.module';
|
||||
import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.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 { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity';
|
||||
|
||||
@Module({
|
||||
@ -31,7 +30,7 @@ import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/perso
|
||||
'metadata',
|
||||
),
|
||||
ContactCreationManagerModule,
|
||||
CalendarCommonModule,
|
||||
MatchParticipantModule,
|
||||
],
|
||||
providers: [
|
||||
CalendarEventParticipantService,
|
||||
@ -41,7 +40,6 @@ import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/perso
|
||||
CalendarEventParticipantListener,
|
||||
CalendarEventParticipantPersonListener,
|
||||
CalendarEventParticipantWorkspaceMemberListener,
|
||||
AddPersonIdAndWorkspaceMemberIdService,
|
||||
],
|
||||
exports: [CalendarEventParticipantService],
|
||||
})
|
||||
|
||||
@ -4,7 +4,8 @@ import { WorkspaceService } from 'src/engine/core-modules/workspace/services/wor
|
||||
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 { CalendarEventParticipantService } from 'src/modules/calendar/calendar-event-participant-manager/services/calendar-event-participant.service';
|
||||
import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity';
|
||||
import { MatchParticipantService } from 'src/modules/match-participant/match-participant.service';
|
||||
|
||||
export type CalendarEventParticipantMatchParticipantJobData = {
|
||||
workspaceId: string;
|
||||
@ -19,8 +20,8 @@ export type CalendarEventParticipantMatchParticipantJobData = {
|
||||
})
|
||||
export class CalendarEventParticipantMatchParticipantJob {
|
||||
constructor(
|
||||
private readonly calendarEventParticipantService: CalendarEventParticipantService,
|
||||
private readonly workspaceService: WorkspaceService,
|
||||
private readonly matchParticipantService: MatchParticipantService<CalendarEventParticipantWorkspaceEntity>,
|
||||
) {}
|
||||
|
||||
@Process(CalendarEventParticipantMatchParticipantJob.name)
|
||||
@ -33,9 +34,9 @@ export class CalendarEventParticipantMatchParticipantJob {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.calendarEventParticipantService.matchCalendarEventParticipants(
|
||||
workspaceId,
|
||||
await this.matchParticipantService.matchParticipantsAfterPersonOrWorkspaceMemberCreation(
|
||||
email,
|
||||
'calendarEventParticipant',
|
||||
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 { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator';
|
||||
import { CalendarEventParticipantService } from 'src/modules/calendar/calendar-event-participant-manager/services/calendar-event-participant.service';
|
||||
import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity';
|
||||
import { MatchParticipantService } from 'src/modules/match-participant/match-participant.service';
|
||||
|
||||
export type CalendarEventParticipantUnmatchParticipantJobData = {
|
||||
workspaceId: string;
|
||||
@ -18,18 +19,18 @@ export type CalendarEventParticipantUnmatchParticipantJobData = {
|
||||
})
|
||||
export class CalendarEventParticipantUnmatchParticipantJob {
|
||||
constructor(
|
||||
private readonly calendarEventParticipantService: CalendarEventParticipantService,
|
||||
private readonly matchParticipantService: MatchParticipantService<CalendarEventParticipantWorkspaceEntity>,
|
||||
) {}
|
||||
|
||||
@Process(CalendarEventParticipantUnmatchParticipantJob.name)
|
||||
async handle(
|
||||
data: CalendarEventParticipantUnmatchParticipantJobData,
|
||||
): Promise<void> {
|
||||
const { workspaceId, email, personId, workspaceMemberId } = data;
|
||||
const { email, personId, workspaceMemberId } = data;
|
||||
|
||||
await this.calendarEventParticipantService.unmatchCalendarEventParticipants(
|
||||
workspaceId,
|
||||
await this.matchParticipantService.unmatchParticipants(
|
||||
email,
|
||||
'calendarEventParticipant',
|
||||
personId,
|
||||
workspaceMemberId,
|
||||
);
|
||||
|
||||
@ -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 { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event-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 { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity';
|
||||
|
||||
@Injectable()
|
||||
export class CalendarEventParticipantListener {
|
||||
@ -25,9 +25,9 @@ export class CalendarEventParticipantListener {
|
||||
public async handleCalendarEventParticipantMatchedEvent(payload: {
|
||||
workspaceId: string;
|
||||
workspaceMemberId: string;
|
||||
calendarEventParticipants: CalendarEventParticipantWorkspaceEntity[];
|
||||
participants: CalendarEventParticipantWorkspaceEntity[];
|
||||
}): Promise<void> {
|
||||
const calendarEventParticipants = payload.calendarEventParticipants ?? [];
|
||||
const calendarEventParticipants = payload.participants ?? [];
|
||||
|
||||
// TODO: move to a job?
|
||||
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
|
||||
import { isDefined } from 'class-validator';
|
||||
import differenceWith from 'lodash.differencewith';
|
||||
@ -8,12 +7,13 @@ import { Any } from 'typeorm';
|
||||
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
|
||||
import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity';
|
||||
import { CalendarEventParticipantWithCalendarEventId } from 'src/modules/calendar/common/types/calendar-event';
|
||||
import { MatchParticipantService } from 'src/modules/match-participant/match-participant.service';
|
||||
|
||||
@Injectable()
|
||||
export class CalendarEventParticipantService {
|
||||
constructor(
|
||||
private readonly twentyORMManager: TwentyORMManager,
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
private readonly matchParticipantService: MatchParticipantService<CalendarEventParticipantWorkspaceEntity>,
|
||||
) {}
|
||||
|
||||
public async upsertAndDeleteCalendarEventParticipants(
|
||||
@ -103,103 +103,16 @@ export class CalendarEventParticipantService {
|
||||
|
||||
participantsToSave.push(...newCalendarEventParticipants);
|
||||
|
||||
await calendarEventParticipantRepository.save(
|
||||
const savedParticipants = await calendarEventParticipantRepository.save(
|
||||
participantsToSave,
|
||||
{},
|
||||
transactionManager,
|
||||
);
|
||||
}
|
||||
|
||||
public async matchCalendarEventParticipants(
|
||||
workspaceId: string,
|
||||
email: string,
|
||||
personId?: string,
|
||||
workspaceMemberId?: string,
|
||||
) {
|
||||
const calendarEventParticipantRepository =
|
||||
await this.twentyORMManager.getRepository<CalendarEventParticipantWorkspaceEntity>(
|
||||
'calendarEventParticipant',
|
||||
);
|
||||
|
||||
const calendarEventParticipantsToUpdate =
|
||||
await calendarEventParticipantRepository.find({
|
||||
where: {
|
||||
handle: email,
|
||||
},
|
||||
});
|
||||
|
||||
const calendarEventParticipantIdsToUpdate =
|
||||
calendarEventParticipantsToUpdate.map((participant) => participant.id);
|
||||
|
||||
if (personId) {
|
||||
await calendarEventParticipantRepository.update(
|
||||
{
|
||||
id: Any(calendarEventParticipantIdsToUpdate),
|
||||
},
|
||||
{
|
||||
person: {
|
||||
id: personId,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const updatedCalendarEventParticipants =
|
||||
await calendarEventParticipantRepository.find({
|
||||
where: {
|
||||
id: Any(calendarEventParticipantIdsToUpdate),
|
||||
},
|
||||
});
|
||||
|
||||
this.eventEmitter.emit(`calendarEventParticipant.matched`, {
|
||||
workspaceId,
|
||||
workspaceMemberId: null,
|
||||
calendarEventParticipants: updatedCalendarEventParticipants,
|
||||
});
|
||||
}
|
||||
if (workspaceMemberId) {
|
||||
await calendarEventParticipantRepository.update(
|
||||
{
|
||||
id: Any(calendarEventParticipantIdsToUpdate),
|
||||
},
|
||||
{
|
||||
workspaceMember: {
|
||||
id: workspaceMemberId,
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public async unmatchCalendarEventParticipants(
|
||||
workspaceId: string,
|
||||
handle: string,
|
||||
personId?: string,
|
||||
workspaceMemberId?: string,
|
||||
) {
|
||||
const calendarEventParticipantRepository =
|
||||
await this.twentyORMManager.getRepository<CalendarEventParticipantWorkspaceEntity>(
|
||||
'calendarEventParticipant',
|
||||
);
|
||||
|
||||
if (personId) {
|
||||
await calendarEventParticipantRepository.update(
|
||||
{
|
||||
handle,
|
||||
},
|
||||
{
|
||||
person: null,
|
||||
},
|
||||
);
|
||||
}
|
||||
if (workspaceMemberId) {
|
||||
await calendarEventParticipantRepository.update(
|
||||
{
|
||||
handle,
|
||||
},
|
||||
{
|
||||
workspaceMember: null,
|
||||
},
|
||||
);
|
||||
}
|
||||
await this.matchParticipantService.matchParticipants(
|
||||
savedParticipants,
|
||||
'messageParticipant',
|
||||
transactionManager,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,6 @@ import { CalendarBlocklistManagerModule } from 'src/modules/calendar/blocklist-m
|
||||
import { CalendarEventCleanerModule } from 'src/modules/calendar/calendar-event-cleaner/calendar-event-cleaner.module';
|
||||
import { CalendarEventImportManagerModule } from 'src/modules/calendar/calendar-event-import-manager/calendar-event-import-manager.module';
|
||||
import { CalendarEventParticipantManagerModule } from 'src/modules/calendar/calendar-event-participant-manager/calendar-event-participant-manager.module';
|
||||
import { CalendarCommonModule } from 'src/modules/calendar/common/calendar-common.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@ -12,7 +11,6 @@ import { CalendarCommonModule } from 'src/modules/calendar/common/calendar-commo
|
||||
CalendarEventCleanerModule,
|
||||
CalendarEventImportManagerModule,
|
||||
CalendarEventParticipantManagerModule,
|
||||
CalendarCommonModule,
|
||||
],
|
||||
providers: [],
|
||||
exports: [],
|
||||
|
||||
@ -1,11 +0,0 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
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';
|
||||
|
||||
@Module({
|
||||
imports: [WorkspaceDataSourceModule],
|
||||
providers: [AddPersonIdAndWorkspaceMemberIdService],
|
||||
exports: [],
|
||||
})
|
||||
export class CalendarCommonModule {}
|
||||
@ -1,4 +1,4 @@
|
||||
import { MESSAGING_THROTTLE_DURATION } from 'src/modules/messaging/common/constants/messaging-throttle-duration';
|
||||
import { MESSAGING_THROTTLE_DURATION } from 'src/modules/messaging/message-import-manager/constants/messaging-throttle-duration';
|
||||
|
||||
export const isThrottled = (
|
||||
syncStageStartedAt: string | null,
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { ScopedWorkspaceContextFactory } from 'src/engine/twenty-orm/factories/scoped-workspace-context.factory';
|
||||
import { MatchParticipantService } from 'src/modules/match-participant/match-participant.service';
|
||||
|
||||
@Module({
|
||||
imports: [],
|
||||
providers: [ScopedWorkspaceContextFactory, MatchParticipantService],
|
||||
exports: [MatchParticipantService],
|
||||
})
|
||||
export class MatchParticipantModule {}
|
||||
@ -0,0 +1,209 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
|
||||
import { Any } from 'typeorm';
|
||||
|
||||
import { ScopedWorkspaceContextFactory } from 'src/engine/twenty-orm/factories/scoped-workspace-context.factory';
|
||||
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
|
||||
import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity';
|
||||
import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity';
|
||||
import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity';
|
||||
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
|
||||
|
||||
@Injectable()
|
||||
export class MatchParticipantService<
|
||||
ParticipantWorkspaceEntity extends
|
||||
| CalendarEventParticipantWorkspaceEntity
|
||||
| MessageParticipantWorkspaceEntity,
|
||||
> {
|
||||
constructor(
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
private readonly twentyORMManager: TwentyORMManager,
|
||||
private readonly scopedWorkspaceContextFactory: ScopedWorkspaceContextFactory,
|
||||
) {}
|
||||
|
||||
private async getParticipantRepository(
|
||||
objectMetadataName: 'messageParticipant' | 'calendarEventParticipant',
|
||||
) {
|
||||
if (objectMetadataName === 'messageParticipant') {
|
||||
return await this.twentyORMManager.getRepository<MessageParticipantWorkspaceEntity>(
|
||||
objectMetadataName,
|
||||
);
|
||||
}
|
||||
|
||||
return await this.twentyORMManager.getRepository<CalendarEventParticipantWorkspaceEntity>(
|
||||
objectMetadataName,
|
||||
);
|
||||
}
|
||||
|
||||
public async matchParticipants(
|
||||
participants: ParticipantWorkspaceEntity[],
|
||||
objectMetadataName: 'messageParticipant' | 'calendarEventParticipant',
|
||||
transactionManager?: any,
|
||||
) {
|
||||
const participantRepository =
|
||||
await this.getParticipantRepository(objectMetadataName);
|
||||
|
||||
const workspaceId = this.scopedWorkspaceContextFactory.create().workspaceId;
|
||||
|
||||
const participantIds = participants.map((participant) => participant.id);
|
||||
const uniqueParticipantsHandles = [
|
||||
...new Set(participants.map((participant) => participant.handle)),
|
||||
];
|
||||
|
||||
const personRepository =
|
||||
await this.twentyORMManager.getRepository<PersonWorkspaceEntity>(
|
||||
'person',
|
||||
);
|
||||
|
||||
const people = await personRepository.find(
|
||||
{
|
||||
where: {
|
||||
email: Any(uniqueParticipantsHandles),
|
||||
},
|
||||
},
|
||||
transactionManager,
|
||||
);
|
||||
|
||||
const workspaceMemberRepository =
|
||||
await this.twentyORMManager.getRepository<WorkspaceMemberWorkspaceEntity>(
|
||||
'workspaceMember',
|
||||
);
|
||||
|
||||
const workspaceMembers = await workspaceMemberRepository.find(
|
||||
{
|
||||
where: {
|
||||
userEmail: Any(uniqueParticipantsHandles),
|
||||
},
|
||||
},
|
||||
transactionManager,
|
||||
);
|
||||
|
||||
for (const handle of uniqueParticipantsHandles) {
|
||||
const person = people.find((person) => person.email === handle);
|
||||
|
||||
const workspaceMember = workspaceMembers.find(
|
||||
(workspaceMember) => workspaceMember.userEmail === handle,
|
||||
);
|
||||
|
||||
await participantRepository.update(
|
||||
{
|
||||
id: Any(participantIds),
|
||||
handle,
|
||||
},
|
||||
{
|
||||
personId: person?.id,
|
||||
workspaceMemberId: workspaceMember?.id,
|
||||
},
|
||||
transactionManager,
|
||||
);
|
||||
}
|
||||
|
||||
const matchedParticipants = await participantRepository.find(
|
||||
{
|
||||
where: {
|
||||
id: Any(participantIds),
|
||||
handle: Any(uniqueParticipantsHandles),
|
||||
},
|
||||
},
|
||||
transactionManager,
|
||||
);
|
||||
|
||||
this.eventEmitter.emit(`${objectMetadataName}.matched`, {
|
||||
workspaceId,
|
||||
workspaceMemberId: null,
|
||||
participants: matchedParticipants,
|
||||
});
|
||||
}
|
||||
|
||||
public async matchParticipantsAfterPersonOrWorkspaceMemberCreation(
|
||||
handle: string,
|
||||
objectMetadataName: 'messageParticipant' | 'calendarEventParticipant',
|
||||
personId?: string,
|
||||
workspaceMemberId?: string,
|
||||
) {
|
||||
const participantRepository =
|
||||
await this.getParticipantRepository(objectMetadataName);
|
||||
|
||||
const workspaceId = this.scopedWorkspaceContextFactory.create().workspaceId;
|
||||
|
||||
const participantsToUpdate = await participantRepository.find({
|
||||
where: {
|
||||
handle,
|
||||
},
|
||||
});
|
||||
|
||||
const participantIdsToUpdate = participantsToUpdate.map(
|
||||
(participant) => participant.id,
|
||||
);
|
||||
|
||||
if (personId) {
|
||||
await participantRepository.update(
|
||||
{
|
||||
id: Any(participantIdsToUpdate),
|
||||
},
|
||||
{
|
||||
person: {
|
||||
id: personId,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const updatedParticipants = await participantRepository.find({
|
||||
where: {
|
||||
id: Any(participantIdsToUpdate),
|
||||
},
|
||||
});
|
||||
|
||||
this.eventEmitter.emit(`${objectMetadataName}.matched`, {
|
||||
workspaceId,
|
||||
workspaceMemberId: null,
|
||||
participants: updatedParticipants,
|
||||
});
|
||||
}
|
||||
|
||||
if (workspaceMemberId) {
|
||||
await participantRepository.update(
|
||||
{
|
||||
id: Any(participantIdsToUpdate),
|
||||
},
|
||||
{
|
||||
workspaceMember: {
|
||||
id: workspaceMemberId,
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public async unmatchParticipants(
|
||||
handle: string,
|
||||
objectMetadataName: 'messageParticipant' | 'calendarEventParticipant',
|
||||
personId?: string,
|
||||
workspaceMemberId?: string,
|
||||
) {
|
||||
const participantRepository =
|
||||
await this.getParticipantRepository(objectMetadataName);
|
||||
|
||||
if (personId) {
|
||||
await participantRepository.update(
|
||||
{
|
||||
handle,
|
||||
},
|
||||
{
|
||||
person: null,
|
||||
},
|
||||
);
|
||||
}
|
||||
if (workspaceMemberId) {
|
||||
await participantRepository.update(
|
||||
{
|
||||
handle,
|
||||
},
|
||||
{
|
||||
workspaceMember: null,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,18 +1,10 @@
|
||||
import { HttpModule } from '@nestjs/axios';
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { AnalyticsModule } from 'src/engine/core-modules/analytics/analytics.module';
|
||||
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 { 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 { MessagingChannelSyncStatusService } from 'src/modules/messaging/common/services/messaging-channel-sync-status.service';
|
||||
import { MessagingErrorHandlingService } from 'src/modules/messaging/common/services/messaging-error-handling.service';
|
||||
import { MessagingFetchByBatchesService } from 'src/modules/messaging/common/services/messaging-fetch-by-batch.service';
|
||||
import { MessagingMessageThreadService } from 'src/modules/messaging/common/services/messaging-message-thread.service';
|
||||
import { MessagingMessageService } from 'src/modules/messaging/common/services/messaging-message.service';
|
||||
import { MessagingTelemetryService } from 'src/modules/messaging/common/services/messaging-telemetry.service';
|
||||
import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity';
|
||||
import { MessageThreadWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-thread.workspace-entity';
|
||||
import { MessageWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message.workspace-entity';
|
||||
@ -20,10 +12,6 @@ import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/perso
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
HttpModule.register({
|
||||
baseURL: 'https://www.googleapis.com/batch/gmail/v1',
|
||||
}),
|
||||
AnalyticsModule,
|
||||
WorkspaceDataSourceModule,
|
||||
ObjectMetadataRepositoryModule.forFeature([
|
||||
PersonWorkspaceEntity,
|
||||
@ -33,22 +21,7 @@ import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/perso
|
||||
]),
|
||||
TypeOrmModule.forFeature([FeatureFlagEntity], 'core'),
|
||||
],
|
||||
providers: [
|
||||
MessagingMessageService,
|
||||
MessagingMessageThreadService,
|
||||
MessagingErrorHandlingService,
|
||||
MessagingTelemetryService,
|
||||
MessagingChannelSyncStatusService,
|
||||
MessagingFetchByBatchesService,
|
||||
AddPersonIdAndWorkspaceMemberIdService,
|
||||
],
|
||||
exports: [
|
||||
MessagingMessageService,
|
||||
MessagingMessageThreadService,
|
||||
MessagingErrorHandlingService,
|
||||
MessagingTelemetryService,
|
||||
MessagingChannelSyncStatusService,
|
||||
MessagingFetchByBatchesService,
|
||||
],
|
||||
providers: [MessagingChannelSyncStatusService],
|
||||
exports: [MessagingChannelSyncStatusService],
|
||||
})
|
||||
export class MessagingCommonModule {}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { HttpModule } from '@nestjs/axios';
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
@ -9,24 +10,22 @@ import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/works
|
||||
import { BlocklistWorkspaceEntity } from 'src/modules/blocklist/standard-objects/blocklist.workspace-entity';
|
||||
import { EmailAliasManagerModule } from 'src/modules/connected-account/email-alias-manager/email-alias-manager.module';
|
||||
import { OAuth2ClientManagerModule } from 'src/modules/connected-account/oauth2-client-manager/oauth2-client-manager.module';
|
||||
import { RefreshAccessTokenManagerModule } from 'src/modules/connected-account/refresh-access-token-manager/refresh-access-token-manager.module';
|
||||
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
|
||||
import { MessagingCommonModule } from 'src/modules/messaging/common/messaging-common.module';
|
||||
import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity';
|
||||
import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
||||
import { MessagingGmailClientProvider } from 'src/modules/messaging/message-import-manager/drivers/gmail/providers/messaging-gmail-client.provider';
|
||||
import { MessagingGmailFetchByBatchesService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-fetch-by-batch.service';
|
||||
import { MessagingGmailFetchMessagesByBatchesService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-fetch-messages-by-batches.service';
|
||||
import { MessagingGmailFetchMessageIdsToExcludeService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-fetch-messages-ids-to-exclude.service';
|
||||
import { MessagingGmailFullMessageListFetchService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-full-message-list-fetch.service';
|
||||
import { MessagingGmailHistoryService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-history.service';
|
||||
import { MessagingGmailMessagesImportService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-messages-import.service';
|
||||
import { MessagingGmailPartialMessageListFetchService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-partial-message-list-fetch.service';
|
||||
import { MessagingSaveMessagesAndEnqueueContactCreationService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-save-messages-and-enqueue-contact-creation.service';
|
||||
import { MessageParticipantManagerModule } from 'src/modules/messaging/message-participant-manager/message-participant-manager.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
RefreshAccessTokenManagerModule,
|
||||
HttpModule.register({
|
||||
baseURL: 'https://www.googleapis.com/batch/gmail/v1',
|
||||
}),
|
||||
EnvironmentModule,
|
||||
ObjectMetadataRepositoryModule.forFeature([
|
||||
ConnectedAccountWorkspaceEntity,
|
||||
@ -45,20 +44,15 @@ import { MessageParticipantManagerModule } from 'src/modules/messaging/message-p
|
||||
providers: [
|
||||
MessagingGmailClientProvider,
|
||||
MessagingGmailHistoryService,
|
||||
MessagingGmailFetchByBatchesService,
|
||||
MessagingGmailFetchMessagesByBatchesService,
|
||||
MessagingGmailPartialMessageListFetchService,
|
||||
MessagingGmailFullMessageListFetchService,
|
||||
MessagingGmailMessagesImportService,
|
||||
MessagingGmailFetchMessageIdsToExcludeService,
|
||||
MessagingSaveMessagesAndEnqueueContactCreationService,
|
||||
],
|
||||
exports: [
|
||||
MessagingGmailClientProvider,
|
||||
MessagingGmailHistoryService,
|
||||
MessagingGmailFetchByBatchesService,
|
||||
MessagingGmailFetchMessagesByBatchesService,
|
||||
MessagingGmailPartialMessageListFetchService,
|
||||
MessagingGmailFullMessageListFetchService,
|
||||
MessagingGmailMessagesImportService,
|
||||
MessagingGmailFetchMessageIdsToExcludeService,
|
||||
],
|
||||
})
|
||||
|
||||
@ -8,7 +8,7 @@ import { BatchQueries } from 'src/modules/messaging/message-import-manager/types
|
||||
import { createQueriesFromMessageIds } from 'src/modules/messaging/message-import-manager/utils/create-queries-from-message-ids.util';
|
||||
|
||||
@Injectable()
|
||||
export class MessagingFetchByBatchesService {
|
||||
export class MessagingGmailFetchByBatchesService {
|
||||
constructor(private readonly httpService: HttpService) {}
|
||||
|
||||
async fetchAllByBatches(
|
||||
@ -1,14 +1,14 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
|
||||
import { AxiosResponse } from 'axios';
|
||||
import planer from 'planer';
|
||||
import addressparser from 'addressparser';
|
||||
import { AxiosResponse } from 'axios';
|
||||
import { gmail_v1 } from 'googleapis';
|
||||
import planer from 'planer';
|
||||
|
||||
import { assert, assertNotNull } from 'src/utils/assert';
|
||||
import { MessagingGmailFetchByBatchesService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-fetch-by-batch.service';
|
||||
import { GmailMessage } from 'src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-message';
|
||||
import { formatAddressObjectAsParticipants } from 'src/modules/messaging/message-import-manager/utils/format-address-object-as-participants.util';
|
||||
import { MessagingFetchByBatchesService } from 'src/modules/messaging/common/services/messaging-fetch-by-batch.service';
|
||||
import { assert, assertNotNull } from 'src/utils/assert';
|
||||
|
||||
@Injectable()
|
||||
export class MessagingGmailFetchMessagesByBatchesService {
|
||||
@ -17,7 +17,7 @@ export class MessagingGmailFetchMessagesByBatchesService {
|
||||
);
|
||||
|
||||
constructor(
|
||||
private readonly fetchByBatchesService: MessagingFetchByBatchesService,
|
||||
private readonly fetchByBatchesService: MessagingGmailFetchByBatchesService,
|
||||
) {}
|
||||
|
||||
async fetchAllMessages(
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { gmail_v1 } from 'googleapis';
|
||||
import { GaxiosResponse } from 'gaxios';
|
||||
import { gmail_v1 } from 'googleapis';
|
||||
|
||||
import { GmailError } from 'src/modules/messaging/common/services/messaging-error-handling.service';
|
||||
import { MESSAGING_GMAIL_USERS_HISTORY_MAX_RESULT } from 'src/modules/messaging/message-import-manager/drivers/gmail/constants/messaging-gmail-users-history-max-result.constant';
|
||||
import { GmailError } from 'src/modules/messaging/message-import-manager/services/messaging-error-handling.service';
|
||||
|
||||
@Injectable()
|
||||
export class MessagingGmailHistoryService {
|
||||
|
||||
@ -6,15 +6,15 @@ import { MessageQueue } from 'src/engine/integrations/message-queue/message-queu
|
||||
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
|
||||
import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository';
|
||||
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
|
||||
import { isThrottled } from 'src/modules/connected-account/utils/is-throttled';
|
||||
import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository';
|
||||
import { MessagingTelemetryService } from 'src/modules/messaging/common/services/messaging-telemetry.service';
|
||||
import {
|
||||
MessageChannelSyncStage,
|
||||
MessageChannelWorkspaceEntity,
|
||||
} from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
||||
import { MessagingGmailFullMessageListFetchService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-full-message-list-fetch.service';
|
||||
import { MessagingGmailPartialMessageListFetchService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-partial-message-list-fetch.service';
|
||||
import { isThrottled } from 'src/modules/connected-account/utils/is-throttled';
|
||||
import { MessagingFullMessageListFetchService } from 'src/modules/messaging/message-import-manager/services/messaging-full-message-list-fetch.service';
|
||||
import { MessagingPartialMessageListFetchService } from 'src/modules/messaging/message-import-manager/services/messaging-partial-message-list-fetch.service';
|
||||
import { MessagingTelemetryService } from 'src/modules/messaging/monitoring/services/messaging-telemetry.service';
|
||||
|
||||
export type MessagingMessageListFetchJobData = {
|
||||
messageChannelId: string;
|
||||
@ -29,8 +29,8 @@ export class MessagingMessageListFetchJob {
|
||||
private readonly logger = new Logger(MessagingMessageListFetchJob.name);
|
||||
|
||||
constructor(
|
||||
private readonly gmailFullMessageListFetchService: MessagingGmailFullMessageListFetchService,
|
||||
private readonly gmailPartialMessageListFetchV2Service: MessagingGmailPartialMessageListFetchService,
|
||||
private readonly messagingFullMessageListFetchService: MessagingFullMessageListFetchService,
|
||||
private readonly messagingPartialMessageListFetchService: MessagingPartialMessageListFetchService,
|
||||
@InjectObjectMetadataRepository(ConnectedAccountWorkspaceEntity)
|
||||
private readonly connectedAccountRepository: ConnectedAccountRepository,
|
||||
@InjectObjectMetadataRepository(MessageChannelWorkspaceEntity)
|
||||
@ -95,7 +95,7 @@ export class MessagingMessageListFetchJob {
|
||||
messageChannelId: messageChannel.id,
|
||||
});
|
||||
|
||||
await this.gmailPartialMessageListFetchV2Service.processMessageListFetch(
|
||||
await this.messagingPartialMessageListFetchService.processMessageListFetch(
|
||||
messageChannel,
|
||||
connectedAccount,
|
||||
workspaceId,
|
||||
@ -122,7 +122,7 @@ export class MessagingMessageListFetchJob {
|
||||
messageChannelId: messageChannel.id,
|
||||
});
|
||||
|
||||
await this.gmailFullMessageListFetchService.processMessageListFetch(
|
||||
await this.messagingFullMessageListFetchService.processMessageListFetch(
|
||||
messageChannel,
|
||||
connectedAccount,
|
||||
workspaceId,
|
||||
|
||||
@ -6,14 +6,14 @@ import { MessageQueue } from 'src/engine/integrations/message-queue/message-queu
|
||||
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
|
||||
import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository';
|
||||
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
|
||||
import { isThrottled } from 'src/modules/connected-account/utils/is-throttled';
|
||||
import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository';
|
||||
import { MessagingTelemetryService } from 'src/modules/messaging/common/services/messaging-telemetry.service';
|
||||
import {
|
||||
MessageChannelSyncStage,
|
||||
MessageChannelWorkspaceEntity,
|
||||
} from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
||||
import { MessagingGmailMessagesImportService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-messages-import.service';
|
||||
import { isThrottled } from 'src/modules/connected-account/utils/is-throttled';
|
||||
import { MessagingMessagesImportService } from 'src/modules/messaging/message-import-manager/services/messaging-messages-import.service';
|
||||
import { MessagingTelemetryService } from 'src/modules/messaging/monitoring/services/messaging-telemetry.service';
|
||||
|
||||
export type MessagingMessagesImportJobData = {
|
||||
messageChannelId: string;
|
||||
@ -28,7 +28,7 @@ export class MessagingMessagesImportJob {
|
||||
constructor(
|
||||
@InjectObjectMetadataRepository(ConnectedAccountWorkspaceEntity)
|
||||
private readonly connectedAccountRepository: ConnectedAccountRepository,
|
||||
private readonly gmailFetchMessageContentFromCacheService: MessagingGmailMessagesImportService,
|
||||
private readonly gmailFetchMessageContentFromCacheService: MessagingMessagesImportService,
|
||||
@InjectObjectMetadataRepository(MessageChannelWorkspaceEntity)
|
||||
private readonly messageChannelRepository: MessageChannelRepository,
|
||||
private readonly messagingTelemetryService: MessagingTelemetryService,
|
||||
|
||||
@ -1,9 +1,14 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { BillingModule } from 'src/engine/core-modules/billing/billing.module';
|
||||
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
|
||||
import { TwentyORMModule } from 'src/engine/twenty-orm/twenty-orm.module';
|
||||
import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
|
||||
import { EmailAliasManagerModule } from 'src/modules/connected-account/email-alias-manager/email-alias-manager.module';
|
||||
import { RefreshAccessTokenManagerModule } from 'src/modules/connected-account/refresh-access-token-manager/refresh-access-token-manager.module';
|
||||
import { MessagingCommonModule } from 'src/modules/messaging/common/messaging-common.module';
|
||||
import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
||||
import { MessagingSingleMessageImportCommand } from 'src/modules/messaging/message-import-manager/commands/messaging-single-message-import.command';
|
||||
@ -20,11 +25,19 @@ import { MessagingMessageListFetchJob } from 'src/modules/messaging/message-impo
|
||||
import { MessagingMessagesImportJob } from 'src/modules/messaging/message-import-manager/jobs/messaging-messages-import.job';
|
||||
import { MessagingOngoingStaleJob } from 'src/modules/messaging/message-import-manager/jobs/messaging-ongoing-stale.job';
|
||||
import { MessagingMessageImportManagerMessageChannelListener } from 'src/modules/messaging/message-import-manager/listeners/messaging-import-manager-message-channel.listener';
|
||||
import { BillingModule } from 'src/engine/core-modules/billing/billing.module';
|
||||
import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
|
||||
import { MessagingErrorHandlingService } from 'src/modules/messaging/message-import-manager/services/messaging-error-handling.service';
|
||||
import { MessagingFullMessageListFetchService } from 'src/modules/messaging/message-import-manager/services/messaging-full-message-list-fetch.service';
|
||||
import { MessagingMessageThreadService } from 'src/modules/messaging/message-import-manager/services/messaging-message-thread.service';
|
||||
import { MessagingMessageService } from 'src/modules/messaging/message-import-manager/services/messaging-message.service';
|
||||
import { MessagingMessagesImportService } from 'src/modules/messaging/message-import-manager/services/messaging-messages-import.service';
|
||||
import { MessagingPartialMessageListFetchService } from 'src/modules/messaging/message-import-manager/services/messaging-partial-message-list-fetch.service';
|
||||
import { MessagingSaveMessagesAndEnqueueContactCreationService } from 'src/modules/messaging/message-import-manager/services/messaging-save-messages-and-enqueue-contact-creation.service';
|
||||
import { MessageParticipantManagerModule } from 'src/modules/messaging/message-participant-manager/message-participant-manager.module';
|
||||
import { MessagingMonitoringModule } from 'src/modules/messaging/monitoring/messaging-monitoring.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
RefreshAccessTokenManagerModule,
|
||||
WorkspaceDataSourceModule,
|
||||
MessagingGmailDriverModule,
|
||||
MessagingCommonModule,
|
||||
@ -32,6 +45,10 @@ import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/works
|
||||
TypeOrmModule.forFeature([DataSourceEntity], 'metadata'),
|
||||
TwentyORMModule.forFeature([MessageChannelWorkspaceEntity]),
|
||||
BillingModule,
|
||||
EmailAliasManagerModule,
|
||||
FeatureFlagModule,
|
||||
MessageParticipantManagerModule,
|
||||
MessagingMonitoringModule,
|
||||
],
|
||||
providers: [
|
||||
MessagingMessageListFetchCronCommand,
|
||||
@ -47,6 +64,13 @@ import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/works
|
||||
MessagingAddSingleMessageToCacheForImportJob,
|
||||
MessagingMessageImportManagerMessageChannelListener,
|
||||
MessagingCleanCacheJob,
|
||||
MessagingMessageService,
|
||||
MessagingMessageThreadService,
|
||||
MessagingErrorHandlingService,
|
||||
MessagingPartialMessageListFetchService,
|
||||
MessagingFullMessageListFetchService,
|
||||
MessagingMessagesImportService,
|
||||
MessagingSaveMessagesAndEnqueueContactCreationService,
|
||||
],
|
||||
exports: [],
|
||||
})
|
||||
|
||||
@ -5,11 +5,11 @@ import snakeCase from 'lodash.snakecase';
|
||||
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
|
||||
import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository';
|
||||
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
|
||||
import { MessagingTelemetryService } from 'src/modules/messaging/common/services/messaging-telemetry.service';
|
||||
import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
||||
import { MessagingChannelSyncStatusService } from 'src/modules/messaging/common/services/messaging-channel-sync-status.service';
|
||||
import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository';
|
||||
import { MESSAGING_THROTTLE_MAX_ATTEMPTS } from 'src/modules/messaging/common/constants/messaging-throttle-max-attempts';
|
||||
import { MessagingChannelSyncStatusService } from 'src/modules/messaging/common/services/messaging-channel-sync-status.service';
|
||||
import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
||||
import { MESSAGING_THROTTLE_MAX_ATTEMPTS } from 'src/modules/messaging/message-import-manager/constants/messaging-throttle-max-attempts';
|
||||
import { MessagingTelemetryService } from 'src/modules/messaging/monitoring/services/messaging-telemetry.service';
|
||||
|
||||
type SyncStep =
|
||||
| 'partial-message-list-fetch'
|
||||
@ -1,8 +1,8 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
|
||||
import { EntityManager } from 'typeorm';
|
||||
import { gmail_v1 } from 'googleapis';
|
||||
import { GaxiosResponse } from 'gaxios';
|
||||
import { gmail_v1 } from 'googleapis';
|
||||
import { EntityManager } from 'typeorm';
|
||||
|
||||
import { CacheStorageService } from 'src/engine/integrations/cache-storage/cache-storage.service';
|
||||
import { InjectCacheStorage } from 'src/engine/integrations/cache-storage/decorators/cache-storage.decorator';
|
||||
@ -11,22 +11,22 @@ import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repos
|
||||
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
|
||||
import { MessageChannelMessageAssociationRepository } from 'src/modules/messaging/common/repositories/message-channel-message-association.repository';
|
||||
import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository';
|
||||
import { MessagingChannelSyncStatusService } from 'src/modules/messaging/common/services/messaging-channel-sync-status.service';
|
||||
import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity';
|
||||
import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
||||
import { MESSAGING_GMAIL_EXCLUDED_CATEGORIES } from 'src/modules/messaging/message-import-manager/drivers/gmail/constants/messaging-gmail-excluded-categories';
|
||||
import { MESSAGING_GMAIL_USERS_MESSAGES_LIST_MAX_RESULT } from 'src/modules/messaging/message-import-manager/drivers/gmail/constants/messaging-gmail-users-messages-list-max-result.constant';
|
||||
import { MessagingGmailClientProvider } from 'src/modules/messaging/message-import-manager/drivers/gmail/providers/messaging-gmail-client.provider';
|
||||
import { computeGmailCategoryExcludeSearchFilter } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/compute-gmail-category-excude-search-filter';
|
||||
import {
|
||||
GmailError,
|
||||
MessagingErrorHandlingService,
|
||||
} from 'src/modules/messaging/common/services/messaging-error-handling.service';
|
||||
import { computeGmailCategoryExcludeSearchFilter } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/compute-gmail-category-excude-search-filter';
|
||||
import { MessagingChannelSyncStatusService } from 'src/modules/messaging/common/services/messaging-channel-sync-status.service';
|
||||
import { MessagingGmailClientProvider } from 'src/modules/messaging/message-import-manager/drivers/gmail/providers/messaging-gmail-client.provider';
|
||||
import { MESSAGING_GMAIL_USERS_MESSAGES_LIST_MAX_RESULT } from 'src/modules/messaging/message-import-manager/drivers/gmail/constants/messaging-gmail-users-messages-list-max-result.constant';
|
||||
import { MESSAGING_GMAIL_EXCLUDED_CATEGORIES } from 'src/modules/messaging/message-import-manager/drivers/gmail/constants/messaging-gmail-excluded-categories';
|
||||
} from 'src/modules/messaging/message-import-manager/services/messaging-error-handling.service';
|
||||
|
||||
@Injectable()
|
||||
export class MessagingGmailFullMessageListFetchService {
|
||||
export class MessagingFullMessageListFetchService {
|
||||
private readonly logger = new Logger(
|
||||
MessagingGmailFullMessageListFetchService.name,
|
||||
MessagingFullMessageListFetchService.name,
|
||||
);
|
||||
|
||||
constructor(
|
||||
@ -56,12 +56,11 @@ export class MessagingGmailFullMessageListFetchService {
|
||||
const gmailClient: gmail_v1.Gmail =
|
||||
await this.gmailClientProvider.getGmailClient(connectedAccount);
|
||||
|
||||
const { error: gmailError } =
|
||||
await this.fetchAllMessageIdsFromGmailAndStoreInCache(
|
||||
gmailClient,
|
||||
messageChannel.id,
|
||||
workspaceId,
|
||||
);
|
||||
const { error: gmailError } = await this.fetchAllMessageIdsAndStoreInCache(
|
||||
gmailClient,
|
||||
messageChannel.id,
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
if (gmailError) {
|
||||
await this.gmailErrorHandlingService.handleGmailError(
|
||||
@ -90,7 +89,7 @@ export class MessagingGmailFullMessageListFetchService {
|
||||
);
|
||||
}
|
||||
|
||||
private async fetchAllMessageIdsFromGmailAndStoreInCache(
|
||||
private async fetchAllMessageIdsAndStoreInCache(
|
||||
gmailClient: gmail_v1.Gmail,
|
||||
messageChannelId: string,
|
||||
workspaceId: string,
|
||||
@ -9,11 +9,11 @@ import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/s
|
||||
import { MessageChannelMessageAssociationRepository } from 'src/modules/messaging/common/repositories/message-channel-message-association.repository';
|
||||
import { MessageThreadRepository } from 'src/modules/messaging/common/repositories/message-thread.repository';
|
||||
import { MessageRepository } from 'src/modules/messaging/common/repositories/message.repository';
|
||||
import { MessagingMessageThreadService } from 'src/modules/messaging/common/services/messaging-message-thread.service';
|
||||
import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity';
|
||||
import { MessageThreadWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-thread.workspace-entity';
|
||||
import { MessageWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message.workspace-entity';
|
||||
import { GmailMessage } from 'src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-message';
|
||||
import { MessagingMessageThreadService } from 'src/modules/messaging/message-import-manager/services/messaging-message-thread.service';
|
||||
|
||||
@Injectable()
|
||||
export class MessagingMessageService {
|
||||
@ -14,22 +14,20 @@ import { ConnectedAccountRepository } from 'src/modules/connected-account/reposi
|
||||
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
|
||||
import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository';
|
||||
import { MessagingChannelSyncStatusService } from 'src/modules/messaging/common/services/messaging-channel-sync-status.service';
|
||||
import { MessagingErrorHandlingService } from 'src/modules/messaging/common/services/messaging-error-handling.service';
|
||||
import { MessagingTelemetryService } from 'src/modules/messaging/common/services/messaging-telemetry.service';
|
||||
import {
|
||||
MessageChannelSyncStage,
|
||||
MessageChannelWorkspaceEntity,
|
||||
} from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
||||
import { MESSAGING_GMAIL_USERS_MESSAGES_GET_BATCH_SIZE } from 'src/modules/messaging/message-import-manager/drivers/gmail/constants/messaging-gmail-users-messages-get-batch-size.constant';
|
||||
import { MessagingGmailFetchMessagesByBatchesService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-fetch-messages-by-batches.service';
|
||||
import { MessagingSaveMessagesAndEnqueueContactCreationService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-save-messages-and-enqueue-contact-creation.service';
|
||||
import { MessagingErrorHandlingService } from 'src/modules/messaging/message-import-manager/services/messaging-error-handling.service';
|
||||
import { MessagingSaveMessagesAndEnqueueContactCreationService } from 'src/modules/messaging/message-import-manager/services/messaging-save-messages-and-enqueue-contact-creation.service';
|
||||
import { filterEmails } from 'src/modules/messaging/message-import-manager/utils/filter-emails.util';
|
||||
import { MessagingTelemetryService } from 'src/modules/messaging/monitoring/services/messaging-telemetry.service';
|
||||
|
||||
@Injectable()
|
||||
export class MessagingGmailMessagesImportService {
|
||||
private readonly logger = new Logger(
|
||||
MessagingGmailMessagesImportService.name,
|
||||
);
|
||||
export class MessagingMessagesImportService {
|
||||
private readonly logger = new Logger(MessagingMessagesImportService.name);
|
||||
|
||||
constructor(
|
||||
private readonly fetchMessagesByBatchesService: MessagingGmailFetchMessagesByBatchesService,
|
||||
@ -2,25 +2,25 @@ import { Injectable, Logger } from '@nestjs/common';
|
||||
|
||||
import { gmail_v1 } from 'googleapis';
|
||||
|
||||
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
|
||||
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
|
||||
import { CacheStorageService } from 'src/engine/integrations/cache-storage/cache-storage.service';
|
||||
import { InjectCacheStorage } from 'src/engine/integrations/cache-storage/decorators/cache-storage.decorator';
|
||||
import { CacheStorageNamespace } from 'src/engine/integrations/cache-storage/types/cache-storage-namespace.enum';
|
||||
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
|
||||
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
|
||||
import { MessageChannelMessageAssociationRepository } from 'src/modules/messaging/common/repositories/message-channel-message-association.repository';
|
||||
import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository';
|
||||
import { MessagingChannelSyncStatusService } from 'src/modules/messaging/common/services/messaging-channel-sync-status.service';
|
||||
import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity';
|
||||
import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
||||
import { MessagingGmailClientProvider } from 'src/modules/messaging/message-import-manager/drivers/gmail/providers/messaging-gmail-client.provider';
|
||||
import { MessagingChannelSyncStatusService } from 'src/modules/messaging/common/services/messaging-channel-sync-status.service';
|
||||
import { MessagingGmailFetchMessageIdsToExcludeService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-fetch-messages-ids-to-exclude.service';
|
||||
import { MessagingErrorHandlingService } from 'src/modules/messaging/common/services/messaging-error-handling.service';
|
||||
import { MessagingGmailHistoryService } from 'src/modules/messaging/message-import-manager/drivers/gmail/services/messaging-gmail-history.service';
|
||||
import { MessagingErrorHandlingService } from 'src/modules/messaging/message-import-manager/services/messaging-error-handling.service';
|
||||
|
||||
@Injectable()
|
||||
export class MessagingGmailPartialMessageListFetchService {
|
||||
export class MessagingPartialMessageListFetchService {
|
||||
private readonly logger = new Logger(
|
||||
MessagingGmailPartialMessageListFetchService.name,
|
||||
MessagingPartialMessageListFetchService.name,
|
||||
);
|
||||
|
||||
constructor(
|
||||
@ -1,30 +1,26 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { EntityManager, Repository } from 'typeorm';
|
||||
import { EntityManager } from 'typeorm';
|
||||
|
||||
import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
|
||||
import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator';
|
||||
import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants';
|
||||
import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service';
|
||||
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
|
||||
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
|
||||
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
|
||||
import {
|
||||
CreateCompanyAndContactJob,
|
||||
CreateCompanyAndContactJobData,
|
||||
} from 'src/modules/contact-creation-manager/jobs/create-company-and-contact.job';
|
||||
import { MessagingMessageService } from 'src/modules/messaging/common/services/messaging-message.service';
|
||||
import {
|
||||
MessageChannelContactAutoCreationPolicy,
|
||||
MessageChannelWorkspaceEntity,
|
||||
} from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
||||
import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity';
|
||||
import {
|
||||
GmailMessage,
|
||||
Participant,
|
||||
ParticipantWithMessageId,
|
||||
} from 'src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-message';
|
||||
import { MessagingMessageService } from 'src/modules/messaging/message-import-manager/services/messaging-message.service';
|
||||
import { MessagingMessageParticipantService } from 'src/modules/messaging/message-participant-manager/services/messaging-message-participant.service';
|
||||
import { isGroupEmail } from 'src/utils/is-group-email';
|
||||
import { isWorkEmail } from 'src/utils/is-work-email';
|
||||
@ -32,14 +28,11 @@ import { isWorkEmail } from 'src/utils/is-work-email';
|
||||
@Injectable()
|
||||
export class MessagingSaveMessagesAndEnqueueContactCreationService {
|
||||
constructor(
|
||||
private readonly workspaceDataSourceService: WorkspaceDataSourceService,
|
||||
@InjectMessageQueue(MessageQueue.contactCreationQueue)
|
||||
private readonly messageQueueService: MessageQueueService,
|
||||
private readonly messageService: MessagingMessageService,
|
||||
private readonly messageParticipantService: MessagingMessageParticipantService,
|
||||
@InjectRepository(FeatureFlagEntity, 'core')
|
||||
private readonly featureFlagRepository: Repository<FeatureFlagEntity>,
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
private readonly twentyORMManager: TwentyORMManager,
|
||||
) {}
|
||||
|
||||
async saveMessagesAndEnqueueContactCreationJob(
|
||||
@ -48,14 +41,9 @@ export class MessagingSaveMessagesAndEnqueueContactCreationService {
|
||||
connectedAccount: ConnectedAccountWorkspaceEntity,
|
||||
workspaceId: string,
|
||||
) {
|
||||
const workspaceDataSource =
|
||||
await this.workspaceDataSourceService.connectToWorkspaceDataSource(
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
const handleAliases = connectedAccount.handleAliases?.split(',') || [];
|
||||
|
||||
let savedMessageParticipants: MessageParticipantWorkspaceEntity[] = [];
|
||||
const workspaceDataSource = await this.twentyORMManager.getDatasource();
|
||||
|
||||
const participantsWithMessageId = await workspaceDataSource?.transaction(
|
||||
async (transactionManager: EntityManager) => {
|
||||
@ -114,23 +102,15 @@ export class MessagingSaveMessagesAndEnqueueContactCreationService {
|
||||
: [];
|
||||
});
|
||||
|
||||
savedMessageParticipants =
|
||||
await this.messageParticipantService.saveMessageParticipants(
|
||||
participantsWithMessageId,
|
||||
workspaceId,
|
||||
transactionManager,
|
||||
);
|
||||
await this.messageParticipantService.saveMessageParticipants(
|
||||
participantsWithMessageId,
|
||||
transactionManager,
|
||||
);
|
||||
|
||||
return participantsWithMessageId;
|
||||
},
|
||||
);
|
||||
|
||||
this.eventEmitter.emit(`messageParticipant.matched`, {
|
||||
workspaceId,
|
||||
workspaceMemberId: connectedAccount.accountOwnerId,
|
||||
messageParticipants: savedMessageParticipants,
|
||||
});
|
||||
|
||||
if (messageChannel.isContactAutoCreationEnabled) {
|
||||
const contactsToCreate = participantsWithMessageId.filter(
|
||||
(participant) => participant.shouldCreateContact,
|
||||
@ -1,4 +1,4 @@
|
||||
import { isEmailBlocklisted } from 'src/modules/calendar-messaging-participant-manager/utils/is-email-blocklisted.util';
|
||||
import { isEmailBlocklisted } from 'src/modules/blocklist/utils/is-email-blocklisted.util';
|
||||
import { GmailMessage } from 'src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-message';
|
||||
|
||||
// Todo: refactor this into several utils
|
||||
|
||||
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,19 +1,19 @@
|
||||
import { Logger } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { Repository, In } from 'typeorm';
|
||||
import snakeCase from 'lodash.snakecase';
|
||||
import { In, Repository } from 'typeorm';
|
||||
|
||||
import { BillingService } from 'src/engine/core-modules/billing/billing.service';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.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';
|
||||
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
|
||||
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
|
||||
import { MessageChannelRepository } from 'src/modules/messaging/common/repositories/message-channel.repository';
|
||||
import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
||||
import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator';
|
||||
import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator';
|
||||
import { MessagingTelemetryService } from 'src/modules/messaging/common/services/messaging-telemetry.service';
|
||||
import { BillingService } from 'src/engine/core-modules/billing/billing.service';
|
||||
import { MessagingTelemetryService } from 'src/modules/messaging/monitoring/services/messaging-telemetry.service';
|
||||
|
||||
@Processor(MessageQueue.cronQueue)
|
||||
export class MessagingMessageChannelSyncStatusMonitoringCronJob {
|
||||
|
||||
@ -1,15 +1,18 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { AnalyticsModule } from 'src/engine/core-modules/analytics/analytics.module';
|
||||
import { BillingModule } from 'src/engine/core-modules/billing/billing.module';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
|
||||
import { MessagingCommonModule } from 'src/modules/messaging/common/messaging-common.module';
|
||||
import { MessagingMessageChannelSyncStatusMonitoringCronCommand } from 'src/modules/messaging/monitoring/crons/commands/messaging-message-channel-sync-status-monitoring.cron.command';
|
||||
import { MessagingMessageChannelSyncStatusMonitoringCronJob } from 'src/modules/messaging/monitoring/crons/jobs/messaging-message-channel-sync-status-monitoring.cron';
|
||||
import { BillingModule } from 'src/engine/core-modules/billing/billing.module';
|
||||
import { MessagingTelemetryService } from 'src/modules/messaging/monitoring/services/messaging-telemetry.service';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
AnalyticsModule,
|
||||
MessagingCommonModule,
|
||||
BillingModule,
|
||||
TypeOrmModule.forFeature([Workspace], 'core'),
|
||||
@ -18,7 +21,8 @@ import { BillingModule } from 'src/engine/core-modules/billing/billing.module';
|
||||
providers: [
|
||||
MessagingMessageChannelSyncStatusMonitoringCronCommand,
|
||||
MessagingMessageChannelSyncStatusMonitoringCronJob,
|
||||
MessagingTelemetryService,
|
||||
],
|
||||
exports: [],
|
||||
exports: [MessagingTelemetryService],
|
||||
})
|
||||
export class MessagingMonitoringModule {}
|
||||
|
||||
Reference in New Issue
Block a user