diff --git a/packages/twenty-server/src/engine/integrations/message-queue/jobs.module.ts b/packages/twenty-server/src/engine/integrations/message-queue/jobs.module.ts index f0dfa9a1efa9..4bec99690bc9 100644 --- a/packages/twenty-server/src/engine/integrations/message-queue/jobs.module.ts +++ b/packages/twenty-server/src/engine/integrations/message-queue/jobs.module.ts @@ -11,18 +11,14 @@ import { ObjectMetadataModule } from 'src/engine-metadata/object-metadata/object import { DataSourceModule } from 'src/engine-metadata/data-source/data-source.module'; import { CleanInactiveWorkspaceJob } from 'src/engine/workspace-manager/workspace-cleaner/crons/clean-inactive-workspace.job'; import { TypeORMModule } from 'src/database/typeorm/typeorm.module'; -import { MessagingModule } from 'src/modules/messaging/messaging.module'; import { GmailPartialSyncJob } from 'src/modules/messaging/jobs/gmail-partial-sync.job'; import { EmailSenderJob } from 'src/engine/integrations/email/email-sender.job'; import { UserModule } from 'src/engine/modules/user/user.module'; import { EnvironmentModule } from 'src/engine/integrations/environment/environment.module'; import { FetchAllWorkspacesMessagesJob } from 'src/modules/messaging/commands/crons/fetch-all-workspaces-messages.job'; -import { ConnectedAccountModule } from 'src/modules/connected-account/repositories/connected-account/connected-account.module'; import { MatchMessageParticipantJob } from 'src/modules/messaging/jobs/match-message-participant.job'; import { CreateCompaniesAndContactsAfterSyncJob } from 'src/modules/messaging/jobs/create-companies-and-contacts-after-sync.job'; import { CreateCompaniesAndContactsModule } from 'src/modules/connected-account/auto-companies-and-contacts-creation/create-company-and-contact/create-company-and-contact.module'; -import { MessageChannelModule } from 'src/modules/messaging/repositories/message-channel/message-channel.module'; -import { MessageParticipantModule } from 'src/modules/messaging/repositories/message-participant/message-participant.module'; import { DataSeedDemoWorkspaceModule } from 'src/database/commands/data-seed-demo-workspace/data-seed-demo-workspace.module'; import { DataSeedDemoWorkspaceJob } from 'src/database/commands/data-seed-demo-workspace/jobs/data-seed-demo-workspace.job'; import { DeleteConnectedAccountAssociatedMessagingDataJob } from 'src/modules/messaging/jobs/delete-connected-account-associated-messaging-data.job'; @@ -33,27 +29,31 @@ import { UserWorkspaceModule } from 'src/engine/modules/user-workspace/user-work import { StripeModule } from 'src/engine/modules/billing/stripe/stripe.module'; import { Workspace } from 'src/engine/modules/workspace/workspace.entity'; import { FeatureFlagEntity } from 'src/engine/modules/feature-flag/feature-flag.entity'; -import { CalendarModule } from 'src/modules/calendar/calendar.module'; import { DataSourceEntity } from 'src/engine-metadata/data-source/data-source.entity'; import { GoogleCalendarFullSyncJob } from 'src/modules/calendar/jobs/google-calendar-full-sync.job'; import { CalendarEventCleanerModule } from 'src/modules/calendar/services/calendar-event-cleaner/calendar-event-cleaner.module'; import { RecordPositionBackfillJob } from 'src/engine/api/graphql/workspace-query-runner/jobs/record-position-backfill.job'; import { RecordPositionBackfillModule } from 'src/engine/api/graphql/workspace-query-runner/services/record-position-backfill-module'; import { DeleteConnectedAccountAssociatedCalendarDataJob } from 'src/modules/messaging/jobs/delete-connected-account-associated-calendar-data.job'; +import { GoogleCalendarFullSyncModule } from 'src/modules/calendar/services/google-calendar-full-sync.module'; +import { GoogleAPIRefreshAccessTokenModule } from 'src/modules/connected-account/services/google-api-refresh-access-token/google-api-refresh-access-token.module'; +import { GmailFullSyncModule } from 'src/modules/messaging/services/gmail-full-sync/gmail-full-sync.module'; +import { GmailPartialSyncModule } from 'src/modules/messaging/services/gmail-partial-sync/gmail-partial-sync.module'; +import { MessageParticipantModule } from 'src/modules/messaging/services/message-participant/message-participant.module'; +import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; +import { ConnectedAccountObjectMetadata } from 'src/modules/connected-account/standard-objects/connected-account.object-metadata'; +import { MessageParticipantObjectMetadata } from 'src/modules/messaging/standard-objects/message-participant.object-metadata'; +import { MessageChannelObjectMetadata } from 'src/modules/messaging/standard-objects/message-channel.object-metadata'; @Module({ imports: [ BillingModule, DataSourceModule, - ConnectedAccountModule, CreateCompaniesAndContactsModule, DataSeedDemoWorkspaceModule, EnvironmentModule, HttpModule, - MessagingModule, - MessageParticipantModule, - MessageChannelModule, - CalendarModule, + GoogleCalendarFullSyncModule, ObjectMetadataModule, StripeModule, ThreadCleanerModule, @@ -65,6 +65,15 @@ import { DeleteConnectedAccountAssociatedCalendarDataJob } from 'src/modules/mes UserWorkspaceModule, WorkspaceDataSourceModule, RecordPositionBackfillModule, + GoogleAPIRefreshAccessTokenModule, + GmailFullSyncModule, + GmailPartialSyncModule, + MessageParticipantModule, + ObjectMetadataRepositoryModule.forFeature([ + ConnectedAccountObjectMetadata, + MessageParticipantObjectMetadata, + MessageChannelObjectMetadata, + ]), ], providers: [ { diff --git a/packages/twenty-server/src/engine/object-metadata-repository/metadata-to-repository.mapping.ts b/packages/twenty-server/src/engine/object-metadata-repository/metadata-to-repository.mapping.ts new file mode 100644 index 000000000000..593bde6e5ddf --- /dev/null +++ b/packages/twenty-server/src/engine/object-metadata-repository/metadata-to-repository.mapping.ts @@ -0,0 +1,33 @@ +import { CalendarChannelEventAssociationRepository } from 'src/modules/calendar/repositories/calendar-channel-event-association.repository'; +import { CalendarChannelRepository } from 'src/modules/calendar/repositories/calendar-channel.repository'; +import { CalendarEventAttendeeRepository } from 'src/modules/calendar/repositories/calendar-event-attendee.repository'; +import { CalendarEventRepository } from 'src/modules/calendar/repositories/calendar-event.repository'; +import { CompanyRepository } from 'src/modules/company/repositories/company.repository'; +import { BlocklistRepository } from 'src/modules/connected-account/repositories/blocklist.repository'; +import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; +import { MessageChannelMessageAssociationRepository } from 'src/modules/messaging/repositories/message-channel-message-association.repository'; +import { MessageChannelRepository } from 'src/modules/messaging/repositories/message-channel.repository'; +import { MessageParticipantRepository } from 'src/modules/messaging/repositories/message-participant.repository'; +import { MessageThreadRepository } from 'src/modules/messaging/repositories/message-thread.repository'; +import { MessageRepository } from 'src/modules/messaging/repositories/message.repository'; +import { PersonRepository } from 'src/modules/person/repositories/person.repository'; +import { WorkspaceMemberRepository } from 'src/modules/workspace-member/repositories/workspace-member.repository'; + +export const metadataToRepositoryMapping = { + BlocklistObjectMetadata: BlocklistRepository, + CalendarChannelEventAssociationObjectMetadata: + CalendarChannelEventAssociationRepository, + CalendarChannelObjectMetadata: CalendarChannelRepository, + CalendarEventAttendeeObjectMetadata: CalendarEventAttendeeRepository, + CalendarEventObjectMetadata: CalendarEventRepository, + CompanyObjectMetadata: CompanyRepository, + ConnectedAccountObjectMetadata: ConnectedAccountRepository, + MessageChannelMessageAssociationObjectMetadata: + MessageChannelMessageAssociationRepository, + MessageChannelObjectMetadata: MessageChannelRepository, + MessageObjectMetadata: MessageRepository, + MessageParticipantObjectMetadata: MessageParticipantRepository, + MessageThreadObjectMetadata: MessageThreadRepository, + PersonObjectMetadata: PersonRepository, + WorkspaceMemberObjectMetadata: WorkspaceMemberRepository, +}; diff --git a/packages/twenty-server/src/engine/object-metadata-repository/object-metadata-repository.decorator.ts b/packages/twenty-server/src/engine/object-metadata-repository/object-metadata-repository.decorator.ts new file mode 100644 index 000000000000..d8e35a705e30 --- /dev/null +++ b/packages/twenty-server/src/engine/object-metadata-repository/object-metadata-repository.decorator.ts @@ -0,0 +1,12 @@ +import { Inject } from '@nestjs/common'; + +import { convertClassNameToObjectMetadataName } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/convert-class-to-object-metadata-name.util'; +import { capitalize } from 'src/utils/capitalize'; + +export const InjectObjectMetadataRepository = (objectMetadata: any) => { + const token = `${capitalize( + convertClassNameToObjectMetadataName(objectMetadata.name), + )}Repository`; + + return Inject(token); +}; diff --git a/packages/twenty-server/src/engine/object-metadata-repository/object-metadata-repository.module.ts b/packages/twenty-server/src/engine/object-metadata-repository/object-metadata-repository.module.ts new file mode 100644 index 000000000000..624269b0bf8c --- /dev/null +++ b/packages/twenty-server/src/engine/object-metadata-repository/object-metadata-repository.module.ts @@ -0,0 +1,40 @@ +import { Global, Module, DynamicModule, Provider } from '@nestjs/common'; + +import { metadataToRepositoryMapping } from 'src/engine/object-metadata-repository/metadata-to-repository.mapping'; +import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; +import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; +import { convertClassNameToObjectMetadataName } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/convert-class-to-object-metadata-name.util'; +import { capitalize } from 'src/utils/capitalize'; + +@Global() +@Module({}) +export class ObjectMetadataRepositoryModule { + static forFeature(objectMetadatas): DynamicModule { + const providers: Provider[] = objectMetadatas.map((objectMetadata) => { + const repositoryClass = metadataToRepositoryMapping[objectMetadata.name]; + + if (!repositoryClass) { + throw new Error(`No repository found for ${objectMetadata.name}`); + } + + return { + provide: `${capitalize( + convertClassNameToObjectMetadataName(objectMetadata.name), + )}Repository`, + useFactory: ( + workspaceDataSourceService: WorkspaceDataSourceService, + ) => { + return new repositoryClass(workspaceDataSourceService); + }, + inject: [WorkspaceDataSourceService], + }; + }); + + return { + module: ObjectMetadataRepositoryModule, + imports: [WorkspaceDataSourceModule], + providers: [...providers], + exports: providers, + }; + } +} diff --git a/packages/twenty-server/src/modules/calendar/calendar.module.ts b/packages/twenty-server/src/modules/calendar/calendar.module.ts index 6d688c6c8614..b2aa06eff050 100644 --- a/packages/twenty-server/src/modules/calendar/calendar.module.ts +++ b/packages/twenty-server/src/modules/calendar/calendar.module.ts @@ -1,41 +1,8 @@ import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; - -import { FeatureFlagEntity } from 'src/engine/modules/feature-flag/feature-flag.entity'; -import { EnvironmentModule } from 'src/engine/integrations/environment/environment.module'; -import { CreateCompaniesAndContactsModule } from 'src/modules/connected-account/auto-companies-and-contacts-creation/create-company-and-contact/create-company-and-contact.module'; -import { BlocklistModule } from 'src/modules/connected-account/repositories/blocklist/blocklist.module'; -import { ConnectedAccountModule } from 'src/modules/connected-account/repositories/connected-account/connected-account.module'; -import { CalendarChannelEventAssociationModule } from 'src/modules/calendar/repositories/calendar-channel-event-association/calendar-channel-event-assocation.module'; -import { CalendarChannelModule } from 'src/modules/calendar/repositories/calendar-channel/calendar-channel.module'; -import { CalendarEventAttendeeModule } from 'src/modules/calendar/repositories/calendar-event-attendee/calendar-event-attendee.module'; -import { CalendarEventModule } from 'src/modules/calendar/repositories/calendar-event/calendar-event.module'; -import { CalendarEventCleanerModule } from 'src/modules/calendar/services/calendar-event-cleaner/calendar-event-cleaner.module'; -import { GoogleCalendarFullSyncService } from 'src/modules/calendar/services/google-calendar-full-sync.service'; -import { GoogleCalendarClientProvider } from 'src/modules/calendar/services/providers/google-calendar/google-calendar.provider'; -import { CompanyModule } from 'src/modules/messaging/repositories/company/company.module'; -import { PersonModule } from 'src/modules/person/repositories/person/person.module'; -import { WorkspaceMemberModule } from 'src/modules/workspace-member/repositories/workspace-member/workspace-member.module'; -import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; @Module({ - imports: [ - EnvironmentModule, - WorkspaceDataSourceModule, - ConnectedAccountModule, - CalendarChannelModule, - CalendarChannelEventAssociationModule, - CalendarEventModule, - CalendarEventAttendeeModule, - CreateCompaniesAndContactsModule, - WorkspaceMemberModule, - TypeOrmModule.forFeature([FeatureFlagEntity], 'core'), - CompanyModule, - PersonModule, - BlocklistModule, - CalendarEventCleanerModule, - ], - providers: [GoogleCalendarFullSyncService, GoogleCalendarClientProvider], - exports: [GoogleCalendarFullSyncService], + imports: [], + providers: [], + exports: [], }) export class CalendarModule {} diff --git a/packages/twenty-server/src/modules/calendar/commands/google-calendar-full-sync.command.ts b/packages/twenty-server/src/modules/calendar/commands/google-calendar-full-sync.command.ts index 4401d58f2ff8..bd3f04de748f 100644 --- a/packages/twenty-server/src/modules/calendar/commands/google-calendar-full-sync.command.ts +++ b/packages/twenty-server/src/modules/calendar/commands/google-calendar-full-sync.command.ts @@ -4,11 +4,13 @@ import { Command, CommandRunner, Option } from 'nest-commander'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; -import { ConnectedAccountService } from 'src/modules/connected-account/repositories/connected-account/connected-account.service'; +import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; import { GoogleCalendarFullSyncJobData, GoogleCalendarFullSyncJob, } from 'src/modules/calendar/jobs/google-calendar-full-sync.job'; +import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; +import { ConnectedAccountObjectMetadata } from 'src/modules/connected-account/standard-objects/connected-account.object-metadata'; interface GoogleCalendarFullSyncOptions { workspaceId: string; @@ -23,7 +25,8 @@ export class GoogleCalendarFullSyncCommand extends CommandRunner { constructor( @Inject(MessageQueue.messagingQueue) private readonly messageQueueService: MessageQueueService, - private readonly connectedAccountService: ConnectedAccountService, + @InjectObjectMetadataRepository(ConnectedAccountObjectMetadata) + private readonly connectedAccountRepository: ConnectedAccountRepository, ) { super(); } @@ -48,7 +51,7 @@ export class GoogleCalendarFullSyncCommand extends CommandRunner { private async fetchWorkspaceCalendars(workspaceId: string): Promise { const connectedAccounts = - await this.connectedAccountService.getAll(workspaceId); + await this.connectedAccountRepository.getAll(workspaceId); for (const connectedAccount of connectedAccounts) { await this.messageQueueService.add( diff --git a/packages/twenty-server/src/modules/calendar/commands/workspace-calendar-sync-commands.module.ts b/packages/twenty-server/src/modules/calendar/commands/workspace-calendar-sync-commands.module.ts index bcaa654bb3d8..18e1b88691ca 100644 --- a/packages/twenty-server/src/modules/calendar/commands/workspace-calendar-sync-commands.module.ts +++ b/packages/twenty-server/src/modules/calendar/commands/workspace-calendar-sync-commands.module.ts @@ -1,18 +1,12 @@ import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; -import { FeatureFlagEntity } from 'src/engine/modules/feature-flag/feature-flag.entity'; -import { TypeORMModule } from 'src/database/typeorm/typeorm.module'; -import { DataSourceModule } from 'src/engine-metadata/data-source/data-source.module'; -import { ConnectedAccountModule } from 'src/modules/connected-account/repositories/connected-account/connected-account.module'; import { GoogleCalendarFullSyncCommand } from 'src/modules/calendar/commands/google-calendar-full-sync.command'; +import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; +import { ConnectedAccountObjectMetadata } from 'src/modules/connected-account/standard-objects/connected-account.object-metadata'; @Module({ imports: [ - DataSourceModule, - TypeORMModule, - TypeOrmModule.forFeature([FeatureFlagEntity], 'core'), - ConnectedAccountModule, + ObjectMetadataRepositoryModule.forFeature([ConnectedAccountObjectMetadata]), ], providers: [GoogleCalendarFullSyncCommand], }) diff --git a/packages/twenty-server/src/modules/calendar/jobs/google-calendar-full-sync.job.ts b/packages/twenty-server/src/modules/calendar/jobs/google-calendar-full-sync.job.ts index 9759bbf6b77d..6408e72b6dba 100644 --- a/packages/twenty-server/src/modules/calendar/jobs/google-calendar-full-sync.job.ts +++ b/packages/twenty-server/src/modules/calendar/jobs/google-calendar-full-sync.job.ts @@ -2,7 +2,7 @@ import { Injectable, Logger } from '@nestjs/common'; import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; -import { GoogleAPIsRefreshAccessTokenService } from 'src/modules/connected-account/services/google-apis-refresh-access-token.service'; +import { GoogleAPIRefreshAccessTokenService } from 'src/modules/connected-account/services/google-api-refresh-access-token/google-api-refresh-access-token.service'; import { GoogleCalendarFullSyncService } from 'src/modules/calendar/services/google-calendar-full-sync.service'; export type GoogleCalendarFullSyncJobData = { @@ -18,7 +18,7 @@ export class GoogleCalendarFullSyncJob private readonly logger = new Logger(GoogleCalendarFullSyncJob.name); constructor( - private readonly googleAPIsRefreshAccessTokenService: GoogleAPIsRefreshAccessTokenService, + private readonly googleAPIsRefreshAccessTokenService: GoogleAPIRefreshAccessTokenService, private readonly googleCalendarFullSyncService: GoogleCalendarFullSyncService, ) {} diff --git a/packages/twenty-server/src/modules/calendar/repositories/calendar-channel-event-association/calendar-channel-event-association.service.ts b/packages/twenty-server/src/modules/calendar/repositories/calendar-channel-event-association.repository.ts similarity index 98% rename from packages/twenty-server/src/modules/calendar/repositories/calendar-channel-event-association/calendar-channel-event-association.service.ts rename to packages/twenty-server/src/modules/calendar/repositories/calendar-channel-event-association.repository.ts index 8ea4b89806c2..5162c37bfe28 100644 --- a/packages/twenty-server/src/modules/calendar/repositories/calendar-channel-event-association/calendar-channel-event-association.service.ts +++ b/packages/twenty-server/src/modules/calendar/repositories/calendar-channel-event-association.repository.ts @@ -8,7 +8,7 @@ import { CalendarChannelEventAssociationObjectMetadata } from 'src/modules/calen import { getFlattenedValuesAndValuesStringForBatchRawQuery } from 'src/modules/calendar/utils/getFlattenedValuesAndValuesStringForBatchRawQuery.util'; @Injectable() -export class CalendarChannelEventAssociationService { +export class CalendarChannelEventAssociationRepository { constructor( private readonly workspaceDataSourceService: WorkspaceDataSourceService, ) {} diff --git a/packages/twenty-server/src/modules/calendar/repositories/calendar-channel-event-association/calendar-channel-event-assocation.module.ts b/packages/twenty-server/src/modules/calendar/repositories/calendar-channel-event-association/calendar-channel-event-assocation.module.ts deleted file mode 100644 index 2b044c87f6de..000000000000 --- a/packages/twenty-server/src/modules/calendar/repositories/calendar-channel-event-association/calendar-channel-event-assocation.module.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { CalendarChannelEventAssociationService } from 'src/modules/calendar/repositories/calendar-channel-event-association/calendar-channel-event-association.service'; -import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; - -@Module({ - imports: [WorkspaceDataSourceModule], - providers: [CalendarChannelEventAssociationService], - exports: [CalendarChannelEventAssociationService], -}) -export class CalendarChannelEventAssociationModule {} diff --git a/packages/twenty-server/src/modules/calendar/repositories/calendar-channel/calendar-channel.service.ts b/packages/twenty-server/src/modules/calendar/repositories/calendar-channel.repository.ts similarity index 98% rename from packages/twenty-server/src/modules/calendar/repositories/calendar-channel/calendar-channel.service.ts rename to packages/twenty-server/src/modules/calendar/repositories/calendar-channel.repository.ts index 85921f68c545..6273362d5ca6 100644 --- a/packages/twenty-server/src/modules/calendar/repositories/calendar-channel/calendar-channel.service.ts +++ b/packages/twenty-server/src/modules/calendar/repositories/calendar-channel.repository.ts @@ -7,7 +7,7 @@ import { CalendarChannelObjectMetadata } from 'src/modules/calendar/standard-obj import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; @Injectable() -export class CalendarChannelService { +export class CalendarChannelRepository { constructor( private readonly workspaceDataSourceService: WorkspaceDataSourceService, ) {} diff --git a/packages/twenty-server/src/modules/calendar/repositories/calendar-channel/calendar-channel.module.ts b/packages/twenty-server/src/modules/calendar/repositories/calendar-channel/calendar-channel.module.ts deleted file mode 100644 index 3640b0984000..000000000000 --- a/packages/twenty-server/src/modules/calendar/repositories/calendar-channel/calendar-channel.module.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { CalendarChannelService } from 'src/modules/calendar/repositories/calendar-channel/calendar-channel.service'; -import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; - -@Module({ - imports: [WorkspaceDataSourceModule], - providers: [CalendarChannelService], - exports: [CalendarChannelService], -}) -export class CalendarChannelModule {} diff --git a/packages/twenty-server/src/modules/calendar/repositories/calendar-event-attendee/calendar-event-attendee.service.ts b/packages/twenty-server/src/modules/calendar/repositories/calendar-event-attendee.repository.ts similarity index 99% rename from packages/twenty-server/src/modules/calendar/repositories/calendar-event-attendee/calendar-event-attendee.service.ts rename to packages/twenty-server/src/modules/calendar/repositories/calendar-event-attendee.repository.ts index 737604d66846..39a556d8ea20 100644 --- a/packages/twenty-server/src/modules/calendar/repositories/calendar-event-attendee/calendar-event-attendee.service.ts +++ b/packages/twenty-server/src/modules/calendar/repositories/calendar-event-attendee.repository.ts @@ -9,7 +9,7 @@ import { getFlattenedValuesAndValuesStringForBatchRawQuery } from 'src/modules/c import { CalendarEventAttendee } from 'src/modules/calendar/types/calendar-event'; @Injectable() -export class CalendarEventAttendeeService { +export class CalendarEventAttendeeRepository { constructor( private readonly workspaceDataSourceService: WorkspaceDataSourceService, ) {} diff --git a/packages/twenty-server/src/modules/calendar/repositories/calendar-event-attendee/calendar-event-attendee.module.ts b/packages/twenty-server/src/modules/calendar/repositories/calendar-event-attendee/calendar-event-attendee.module.ts deleted file mode 100644 index 64e015520cd5..000000000000 --- a/packages/twenty-server/src/modules/calendar/repositories/calendar-event-attendee/calendar-event-attendee.module.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { CalendarEventAttendeeService } from 'src/modules/calendar/repositories/calendar-event-attendee/calendar-event-attendee.service'; -import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; - -@Module({ - imports: [WorkspaceDataSourceModule], - providers: [CalendarEventAttendeeService], - exports: [CalendarEventAttendeeService], -}) -export class CalendarEventAttendeeModule {} diff --git a/packages/twenty-server/src/modules/calendar/repositories/calendar-event/calendar-event.service.ts b/packages/twenty-server/src/modules/calendar/repositories/calendar-event.repository.ts similarity index 99% rename from packages/twenty-server/src/modules/calendar/repositories/calendar-event/calendar-event.service.ts rename to packages/twenty-server/src/modules/calendar/repositories/calendar-event.repository.ts index 2a0d81014637..2f23fc1d4040 100644 --- a/packages/twenty-server/src/modules/calendar/repositories/calendar-event/calendar-event.service.ts +++ b/packages/twenty-server/src/modules/calendar/repositories/calendar-event.repository.ts @@ -10,7 +10,7 @@ import { CalendarEvent } from 'src/modules/calendar/types/calendar-event'; import { CalendarEventAttendeeObjectMetadata } from 'src/modules/calendar/standard-objects/calendar-event-attendee.object-metadata'; @Injectable() -export class CalendarEventService { +export class CalendarEventRepository { constructor( private readonly workspaceDataSourceService: WorkspaceDataSourceService, ) {} diff --git a/packages/twenty-server/src/modules/calendar/repositories/calendar-event/calendar-event.module.ts b/packages/twenty-server/src/modules/calendar/repositories/calendar-event/calendar-event.module.ts deleted file mode 100644 index 7d501958f867..000000000000 --- a/packages/twenty-server/src/modules/calendar/repositories/calendar-event/calendar-event.module.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { CalendarEventService } from 'src/modules/calendar/repositories/calendar-event/calendar-event.service'; -import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; - -@Module({ - imports: [WorkspaceDataSourceModule], - providers: [CalendarEventService], - exports: [CalendarEventService], -}) -export class CalendarEventModule {} diff --git a/packages/twenty-server/src/modules/calendar/services/calendar-event-cleaner/calendar-event-cleaner.module.ts b/packages/twenty-server/src/modules/calendar/services/calendar-event-cleaner/calendar-event-cleaner.module.ts index 98c1df1fb18d..2f0d4977aa6d 100644 --- a/packages/twenty-server/src/modules/calendar/services/calendar-event-cleaner/calendar-event-cleaner.module.ts +++ b/packages/twenty-server/src/modules/calendar/services/calendar-event-cleaner/calendar-event-cleaner.module.ts @@ -1,12 +1,13 @@ import { Module } from '@nestjs/common'; -import { TypeORMModule } from 'src/database/typeorm/typeorm.module'; -import { DataSourceModule } from 'src/engine-metadata/data-source/data-source.module'; -import { CalendarEventModule } from 'src/modules/calendar/repositories/calendar-event/calendar-event.module'; +import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; import { CalendarEventCleanerService } from 'src/modules/calendar/services/calendar-event-cleaner/calendar-event-cleaner.service'; +import { CalendarEventObjectMetadata } from 'src/modules/calendar/standard-objects/calendar-event.object-metadata'; @Module({ - imports: [DataSourceModule, TypeORMModule, CalendarEventModule], + imports: [ + ObjectMetadataRepositoryModule.forFeature([CalendarEventObjectMetadata]), + ], providers: [CalendarEventCleanerService], exports: [CalendarEventCleanerService], }) diff --git a/packages/twenty-server/src/modules/calendar/services/calendar-event-cleaner/calendar-event-cleaner.service.ts b/packages/twenty-server/src/modules/calendar/services/calendar-event-cleaner/calendar-event-cleaner.service.ts index c3128a326e5e..c56e046a7f12 100644 --- a/packages/twenty-server/src/modules/calendar/services/calendar-event-cleaner/calendar-event-cleaner.service.ts +++ b/packages/twenty-server/src/modules/calendar/services/calendar-event-cleaner/calendar-event-cleaner.service.ts @@ -1,20 +1,27 @@ import { Injectable } from '@nestjs/common'; -import { CalendarEventService } from 'src/modules/calendar/repositories/calendar-event/calendar-event.service'; +import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; +import { CalendarEventRepository } from 'src/modules/calendar/repositories/calendar-event.repository'; +import { CalendarEventObjectMetadata } from 'src/modules/calendar/standard-objects/calendar-event.object-metadata'; import { deleteUsingPagination } from 'src/modules/messaging/services/thread-cleaner/utils/delete-using-pagination.util'; @Injectable() export class CalendarEventCleanerService { - constructor(private readonly calendarEventService: CalendarEventService) {} + constructor( + @InjectObjectMetadataRepository(CalendarEventObjectMetadata) + private readonly calendarEventRepository: CalendarEventRepository, + ) {} public async cleanWorkspaceCalendarEvents(workspaceId: string) { await deleteUsingPagination( workspaceId, 500, - this.calendarEventService.getNonAssociatedCalendarEventIdsPaginated.bind( - this.calendarEventService, + this.calendarEventRepository.getNonAssociatedCalendarEventIdsPaginated.bind( + this.calendarEventRepository, + ), + this.calendarEventRepository.deleteByIds.bind( + this.calendarEventRepository, ), - this.calendarEventService.deleteByIds.bind(this.calendarEventService), ); } } diff --git a/packages/twenty-server/src/modules/calendar/services/google-calendar-full-sync.module.ts b/packages/twenty-server/src/modules/calendar/services/google-calendar-full-sync.module.ts new file mode 100644 index 000000000000..e744f62b8b6a --- /dev/null +++ b/packages/twenty-server/src/modules/calendar/services/google-calendar-full-sync.module.ts @@ -0,0 +1,37 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { FeatureFlagEntity } from 'src/engine/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 { GoogleCalendarFullSyncService } from 'src/modules/calendar/services/google-calendar-full-sync.service'; +import { CalendarProvidersModule } from 'src/modules/calendar/services/providers/calendar-providers.module'; +import { CalendarChannelEventAssociationObjectMetadata } from 'src/modules/calendar/standard-objects/calendar-channel-event-association.object-metadata'; +import { CalendarChannelObjectMetadata } from 'src/modules/calendar/standard-objects/calendar-channel.object-metadata'; +import { CalendarEventAttendeeObjectMetadata } from 'src/modules/calendar/standard-objects/calendar-event-attendee.object-metadata'; +import { CalendarEventObjectMetadata } from 'src/modules/calendar/standard-objects/calendar-event.object-metadata'; +import { BlocklistObjectMetadata } from 'src/modules/connected-account/standard-objects/blocklist.object-metadata'; +import { ConnectedAccountObjectMetadata } from 'src/modules/connected-account/standard-objects/connected-account.object-metadata'; +import { PersonObjectMetadata } from 'src/modules/person/standard-objects/person.object-metadata'; +import { WorkspaceMemberObjectMetadata } from 'src/modules/workspace-member/standard-objects/workspace-member.object-metadata'; + +@Module({ + imports: [ + CalendarProvidersModule, + ObjectMetadataRepositoryModule.forFeature([ + ConnectedAccountObjectMetadata, + CalendarEventObjectMetadata, + CalendarChannelObjectMetadata, + CalendarChannelEventAssociationObjectMetadata, + CalendarEventAttendeeObjectMetadata, + BlocklistObjectMetadata, + PersonObjectMetadata, + WorkspaceMemberObjectMetadata, + ]), + TypeOrmModule.forFeature([FeatureFlagEntity], 'core'), + WorkspaceDataSourceModule, + ], + providers: [GoogleCalendarFullSyncService], + exports: [GoogleCalendarFullSyncService], +}) +export class GoogleCalendarFullSyncModule {} diff --git a/packages/twenty-server/src/modules/calendar/services/google-calendar-full-sync.service.ts b/packages/twenty-server/src/modules/calendar/services/google-calendar-full-sync.service.ts index a5f10af877e1..d7a7a3abfd51 100644 --- a/packages/twenty-server/src/modules/calendar/services/google-calendar-full-sync.service.ts +++ b/packages/twenty-server/src/modules/calendar/services/google-calendar-full-sync.service.ts @@ -3,23 +3,30 @@ import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; -import { ConnectedAccountService } from 'src/modules/connected-account/repositories/connected-account/connected-account.service'; -import { BlocklistService } from 'src/modules/connected-account/repositories/blocklist/blocklist.service'; +import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; +import { BlocklistRepository } from 'src/modules/connected-account/repositories/blocklist.repository'; import { FeatureFlagEntity, FeatureFlagKeys, } from 'src/engine/modules/feature-flag/feature-flag.entity'; import { GoogleCalendarClientProvider } from 'src/modules/calendar/services/providers/google-calendar/google-calendar.provider'; import { googleCalendarSearchFilterExcludeEmails } from 'src/modules/calendar/utils/google-calendar-search-filter.util'; -import { CalendarChannelEventAssociationService } from 'src/modules/calendar/repositories/calendar-channel-event-association/calendar-channel-event-association.service'; -import { CalendarChannelService } from 'src/modules/calendar/repositories/calendar-channel/calendar-channel.service'; +import { CalendarChannelEventAssociationRepository } from 'src/modules/calendar/repositories/calendar-channel-event-association.repository'; +import { CalendarChannelRepository } from 'src/modules/calendar/repositories/calendar-channel.repository'; 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 { CalendarEventService } from 'src/modules/calendar/repositories/calendar-event/calendar-event.service'; +import { CalendarEventRepository } from 'src/modules/calendar/repositories/calendar-event.repository'; import { formatGoogleCalendarEvent } from 'src/modules/calendar/utils/format-google-calendar-event.util'; import { GoogleCalendarFullSyncJobData } from 'src/modules/calendar/jobs/google-calendar-full-sync.job'; -import { CalendarEventAttendeeService } from 'src/modules/calendar/repositories/calendar-event-attendee/calendar-event-attendee.service'; +import { CalendarEventAttendeeRepository } from 'src/modules/calendar/repositories/calendar-event-attendee.repository'; +import { ConnectedAccountObjectMetadata } from 'src/modules/connected-account/standard-objects/connected-account.object-metadata'; +import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; +import { CalendarEventObjectMetadata } from 'src/modules/calendar/standard-objects/calendar-event.object-metadata'; +import { CalendarChannelObjectMetadata } from 'src/modules/calendar/standard-objects/calendar-channel.object-metadata'; +import { CalendarChannelEventAssociationObjectMetadata } from 'src/modules/calendar/standard-objects/calendar-channel-event-association.object-metadata'; +import { CalendarEventAttendeeObjectMetadata } from 'src/modules/calendar/standard-objects/calendar-event-attendee.object-metadata'; +import { BlocklistObjectMetadata } from 'src/modules/connected-account/standard-objects/blocklist.object-metadata'; @Injectable() export class GoogleCalendarFullSyncService { @@ -29,12 +36,20 @@ export class GoogleCalendarFullSyncService { private readonly googleCalendarClientProvider: GoogleCalendarClientProvider, @Inject(MessageQueue.calendarQueue) private readonly messageQueueService: MessageQueueService, - private readonly connectedAccountService: ConnectedAccountService, - private readonly calendarEventService: CalendarEventService, - private readonly calendarChannelService: CalendarChannelService, - private readonly calendarChannelEventAssociationService: CalendarChannelEventAssociationService, - private readonly calendarEventAttendeesService: CalendarEventAttendeeService, - private readonly blocklistService: BlocklistService, + @InjectObjectMetadataRepository(ConnectedAccountObjectMetadata) + private readonly connectedAccountRepository: ConnectedAccountRepository, + @InjectObjectMetadataRepository(CalendarEventObjectMetadata) + private readonly calendarEventRepository: CalendarEventRepository, + @InjectObjectMetadataRepository(CalendarChannelObjectMetadata) + private readonly calendarChannelRepository: CalendarChannelRepository, + @InjectObjectMetadataRepository( + CalendarChannelEventAssociationObjectMetadata, + ) + private readonly calendarChannelEventAssociationRepository: CalendarChannelEventAssociationRepository, + @InjectObjectMetadataRepository(CalendarEventAttendeeObjectMetadata) + private readonly calendarEventAttendeesRepository: CalendarEventAttendeeRepository, + @InjectObjectMetadataRepository(BlocklistObjectMetadata) + private readonly blocklistRepository: BlocklistRepository, @InjectRepository(FeatureFlagEntity, 'core') private readonly featureFlagRepository: Repository, private readonly workspaceDataSourceService: WorkspaceDataSourceService, @@ -45,7 +60,7 @@ export class GoogleCalendarFullSyncService { connectedAccountId: string, pageToken?: string, ): Promise { - const connectedAccount = await this.connectedAccountService.getById( + const connectedAccount = await this.connectedAccountRepository.getById( connectedAccountId, workspaceId, ); @@ -64,7 +79,7 @@ export class GoogleCalendarFullSyncService { } const calendarChannel = - await this.calendarChannelService.getFirstByConnectedAccountIdOrFail( + await this.calendarChannelRepository.getFirstByConnectedAccountIdOrFail( connectedAccountId, workspaceId, ); @@ -87,7 +102,7 @@ export class GoogleCalendarFullSyncService { isBlocklistEnabledFeatureFlag && isBlocklistEnabledFeatureFlag.value; const blocklist = isBlocklistEnabled - ? await this.blocklistService.getByWorkspaceMemberId( + ? await this.blocklistRepository.getByWorkspaceMemberId( workspaceMemberId, workspaceId, ) @@ -130,7 +145,7 @@ export class GoogleCalendarFullSyncService { startTime = Date.now(); const existingCalendarChannelEventAssociations = - await this.calendarChannelEventAssociationService.getByEventExternalIdsAndCalendarChannelId( + await this.calendarChannelEventAssociationRepository.getByEventExternalIdsAndCalendarChannelId( eventExternalIds, calendarChannelId, workspaceId, @@ -180,7 +195,7 @@ export class GoogleCalendarFullSyncService { ); const iCalUIDCalendarEventIdMap = - await this.calendarEventService.getICalUIDCalendarEventIdMap( + await this.calendarEventRepository.getICalUIDCalendarEventIdMap( eventsToUpdate.map((event) => event.iCalUID), workspaceId, ); @@ -192,31 +207,31 @@ export class GoogleCalendarFullSyncService { ); dataSourceMetadata?.transaction(async (transactionManager) => { - this.calendarEventService.saveCalendarEvents( + this.calendarEventRepository.saveCalendarEvents( eventsToSave, workspaceId, transactionManager, ); - this.calendarEventService.updateCalendarEvents( + this.calendarEventRepository.updateCalendarEvents( eventsToUpdate, workspaceId, transactionManager, ); - this.calendarChannelEventAssociationService.saveCalendarChannelEventAssociations( + this.calendarChannelEventAssociationRepository.saveCalendarChannelEventAssociations( calendarChannelEventAssociationsToSave, workspaceId, transactionManager, ); - this.calendarEventAttendeesService.saveCalendarEventAttendees( + this.calendarEventAttendeesRepository.saveCalendarEventAttendees( attendeesToSave, workspaceId, transactionManager, ); - this.calendarEventAttendeesService.updateCalendarEventAttendees( + this.calendarEventAttendeesRepository.updateCalendarEventAttendees( attendeesToUpdate, iCalUIDCalendarEventIdMap, workspaceId, diff --git a/packages/twenty-server/src/modules/messaging/repositories/company/company.service.ts b/packages/twenty-server/src/modules/company/repositories/company.repository.ts similarity index 95% rename from packages/twenty-server/src/modules/messaging/repositories/company/company.service.ts rename to packages/twenty-server/src/modules/company/repositories/company.repository.ts index d4aa7c8a2a00..162ee88c84ee 100644 --- a/packages/twenty-server/src/modules/messaging/repositories/company/company.service.ts +++ b/packages/twenty-server/src/modules/company/repositories/company.repository.ts @@ -11,9 +11,8 @@ export type CompanyToCreate = { city?: string; }; -// TODO: Move outside of the messaging module @Injectable() -export class CompanyService { +export class CompanyRepository { constructor( private readonly workspaceDataSourceService: WorkspaceDataSourceService, ) {} diff --git a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-company-and-contact/create-company-and-contact.module.ts b/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-company-and-contact/create-company-and-contact.module.ts index a6877df0fd9e..3c0f8e2624e2 100644 --- a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-company-and-contact/create-company-and-contact.module.ts +++ b/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-company-and-contact/create-company-and-contact.module.ts @@ -1,19 +1,20 @@ import { Module } from '@nestjs/common'; -import { PersonModule } from 'src/modules/person/repositories/person/person.module'; -import { WorkspaceMemberModule } from 'src/modules/workspace-member/repositories/workspace-member/workspace-member.module'; import { CreateCompanyAndContactService } from 'src/modules/connected-account/auto-companies-and-contacts-creation/create-company-and-contact/create-company-and-contact.service'; import { CreateCompanyModule } from 'src/modules/connected-account/auto-companies-and-contacts-creation/create-company/create-company.module'; import { CreateContactModule } from 'src/modules/connected-account/auto-companies-and-contacts-creation/create-contact/create-contact.module'; -import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; +import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; +import { PersonObjectMetadata } from 'src/modules/person/standard-objects/person.object-metadata'; +import { WorkspaceMemberObjectMetadata } from 'src/modules/workspace-member/standard-objects/workspace-member.object-metadata'; @Module({ imports: [ - WorkspaceDataSourceModule, CreateContactModule, CreateCompanyModule, - WorkspaceMemberModule, - PersonModule, + ObjectMetadataRepositoryModule.forFeature([ + PersonObjectMetadata, + WorkspaceMemberObjectMetadata, + ]), ], providers: [CreateCompanyAndContactService], exports: [CreateCompanyAndContactService], diff --git a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-company-and-contact/create-company-and-contact.service.ts b/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-company-and-contact/create-company-and-contact.service.ts index 0462bc075646..cf1227048f06 100644 --- a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-company-and-contact/create-company-and-contact.service.ts +++ b/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-company-and-contact/create-company-and-contact.service.ts @@ -7,19 +7,24 @@ import { Participant } from 'src/modules/messaging/types/gmail-message'; import { getDomainNameFromHandle } from 'src/modules/messaging/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 { PersonService } from 'src/modules/person/repositories/person/person.service'; -import { WorkspaceMemberService } from 'src/modules/workspace-member/repositories/workspace-member/workspace-member.service'; +import { PersonRepository } from 'src/modules/person/repositories/person.repository'; +import { WorkspaceMemberRepository } from 'src/modules/workspace-member/repositories/workspace-member.repository'; import { getUniqueParticipantsAndHandles } from 'src/modules/messaging/utils/get-unique-participants-and-handles.util'; import { filterOutParticipantsFromCompanyOrWorkspace } from 'src/modules/messaging/utils/filter-out-participants-from-company-or-workspace.util'; import { isWorkEmail } from 'src/utils/is-work-email'; +import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; +import { PersonObjectMetadata } from 'src/modules/person/standard-objects/person.object-metadata'; +import { WorkspaceMemberObjectMetadata } from 'src/modules/workspace-member/standard-objects/workspace-member.object-metadata'; @Injectable() export class CreateCompanyAndContactService { constructor( - private readonly personService: PersonService, private readonly createContactService: CreateContactService, private readonly createCompaniesService: CreateCompanyService, - private readonly workspaceMemberService: WorkspaceMemberService, + @InjectObjectMetadataRepository(PersonObjectMetadata) + private readonly personRepository: PersonRepository, + @InjectObjectMetadataRepository(WorkspaceMemberObjectMetadata) + private readonly workspaceMemberRepository: WorkspaceMemberRepository, ) {} async createCompaniesAndContacts( @@ -36,7 +41,7 @@ export class CreateCompanyAndContactService { const isContactAutoCreationForNonWorkEmailsEnabled = false; const workspaceMembers = - await this.workspaceMemberService.getAllByWorkspaceId( + await this.workspaceMemberRepository.getAllByWorkspaceId( workspaceId, transactionManager, ); @@ -55,7 +60,7 @@ export class CreateCompanyAndContactService { return; } - const alreadyCreatedContacts = await this.personService.getByEmails( + const alreadyCreatedContacts = await this.personRepository.getByEmails( uniqueHandles, workspaceId, ); diff --git a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-company/create-company.module.ts b/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-company/create-company.module.ts index 31e2e68c74d7..c353146d8dcb 100644 --- a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-company/create-company.module.ts +++ b/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-company/create-company.module.ts @@ -1,11 +1,11 @@ import { Module } from '@nestjs/common'; -import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; +import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; +import { CompanyObjectMetadata } from 'src/modules/company/standard-objects/company.object-metadata'; import { CreateCompanyService } from 'src/modules/connected-account/auto-companies-and-contacts-creation/create-company/create-company.service'; -import { CompanyModule } from 'src/modules/messaging/repositories/company/company.module'; @Module({ - imports: [WorkspaceDataSourceModule, CompanyModule], + imports: [ObjectMetadataRepositoryModule.forFeature([CompanyObjectMetadata])], providers: [CreateCompanyService], exports: [CreateCompanyService], }) diff --git a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-company/create-company.service.ts b/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-company/create-company.service.ts index 4052b1cbea6a..57397208702d 100644 --- a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-company/create-company.service.ts +++ b/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-company/create-company.service.ts @@ -4,13 +4,18 @@ import { EntityManager } from 'typeorm'; import { v4 } from 'uuid'; import axios, { AxiosInstance } from 'axios'; -import { CompanyService } from 'src/modules/messaging/repositories/company/company.service'; +import { CompanyRepository } from 'src/modules/company/repositories/company.repository'; import { getCompanyNameFromDomainName } from 'src/modules/messaging/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() export class CreateCompanyService { private readonly httpService: AxiosInstance; - constructor(private readonly companyService: CompanyService) { + constructor( + @InjectObjectMetadataRepository(CompanyObjectMetadata) + private readonly companyRepository: CompanyRepository, + ) { this.httpService = axios.create({ baseURL: 'https://companies.twenty.com', }); @@ -30,7 +35,7 @@ export class CreateCompanyService { const uniqueDomainNames = [...new Set(domainNames)]; const existingCompanies = - await this.companyService.getExistingCompaniesByDomainNames( + await this.companyRepository.getExistingCompaniesByDomainNames( uniqueDomainNames, workspaceId, transactionManager, @@ -80,7 +85,7 @@ export class CreateCompanyService { const { name, city } = await this.getCompanyInfoFromDomainName(domainName); - this.companyService.createCompany( + this.companyRepository.createCompany( workspaceId, { id: companyId, diff --git a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-contact/create-contact.module.ts b/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-contact/create-contact.module.ts index faa9404258a5..bd3eaa1bde6f 100644 --- a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-contact/create-contact.module.ts +++ b/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-contact/create-contact.module.ts @@ -1,11 +1,11 @@ import { Module } from '@nestjs/common'; -import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; +import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; import { CreateContactService } from 'src/modules/connected-account/auto-companies-and-contacts-creation/create-contact/create-contact.service'; -import { PersonModule } from 'src/modules/person/repositories/person/person.module'; +import { PersonObjectMetadata } from 'src/modules/person/standard-objects/person.object-metadata'; @Module({ - imports: [WorkspaceDataSourceModule, PersonModule], + imports: [ObjectMetadataRepositoryModule.forFeature([PersonObjectMetadata])], providers: [CreateContactService], exports: [CreateContactService], }) diff --git a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-contact/create-contact.service.ts b/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-contact/create-contact.service.ts index c96bbc2fda81..be3db3574917 100644 --- a/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-contact/create-contact.service.ts +++ b/packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/create-contact/create-contact.service.ts @@ -3,8 +3,10 @@ import { Injectable } from '@nestjs/common'; import { EntityManager } from 'typeorm'; import { v4 } from 'uuid'; -import { PersonService } from 'src/modules/person/repositories/person/person.service'; +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 { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; +import { PersonObjectMetadata } from 'src/modules/person/standard-objects/person.object-metadata'; type ContactToCreate = { handle: string; @@ -22,7 +24,10 @@ type FormattedContactToCreate = { @Injectable() export class CreateContactService { - constructor(private readonly personService: PersonService) {} + constructor( + @InjectObjectMetadataRepository(PersonObjectMetadata) + private readonly personRepository: PersonRepository, + ) {} public formatContacts( contactsToCreate: ContactToCreate[], @@ -54,7 +59,7 @@ export class CreateContactService { const formattedContacts = this.formatContacts(contactsToCreate); - await this.personService.createPeople( + await this.personRepository.createPeople( formattedContacts, workspaceId, transactionManager, diff --git a/packages/twenty-server/src/modules/connected-account/repositories/blocklist/blocklist.service.ts b/packages/twenty-server/src/modules/connected-account/repositories/blocklist.repository.ts similarity index 96% rename from packages/twenty-server/src/modules/connected-account/repositories/blocklist/blocklist.service.ts rename to packages/twenty-server/src/modules/connected-account/repositories/blocklist.repository.ts index f8ff607e83cf..5b7fa2f1f608 100644 --- a/packages/twenty-server/src/modules/connected-account/repositories/blocklist/blocklist.service.ts +++ b/packages/twenty-server/src/modules/connected-account/repositories/blocklist.repository.ts @@ -7,7 +7,7 @@ import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metada import { BlocklistObjectMetadata } from 'src/modules/connected-account/standard-objects/blocklist.object-metadata'; @Injectable() -export class BlocklistService { +export class BlocklistRepository { constructor( private readonly workspaceDataSourceService: WorkspaceDataSourceService, ) {} diff --git a/packages/twenty-server/src/modules/connected-account/repositories/blocklist/blocklist.module.ts b/packages/twenty-server/src/modules/connected-account/repositories/blocklist/blocklist.module.ts deleted file mode 100644 index 08e623074685..000000000000 --- a/packages/twenty-server/src/modules/connected-account/repositories/blocklist/blocklist.module.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { BlocklistService } from 'src/modules/connected-account/repositories/blocklist/blocklist.service'; -import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; - -@Module({ - imports: [WorkspaceDataSourceModule], - providers: [BlocklistService], - exports: [BlocklistService], -}) -export class BlocklistModule {} diff --git a/packages/twenty-server/src/modules/connected-account/repositories/connected-account/connected-account.service.ts b/packages/twenty-server/src/modules/connected-account/repositories/connected-account.repository.ts similarity index 99% rename from packages/twenty-server/src/modules/connected-account/repositories/connected-account/connected-account.service.ts rename to packages/twenty-server/src/modules/connected-account/repositories/connected-account.repository.ts index 739da879afc8..5a46a1a8e5f5 100644 --- a/packages/twenty-server/src/modules/connected-account/repositories/connected-account/connected-account.service.ts +++ b/packages/twenty-server/src/modules/connected-account/repositories/connected-account.repository.ts @@ -7,7 +7,7 @@ import { ConnectedAccountObjectMetadata } from 'src/modules/connected-account/st import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; @Injectable() -export class ConnectedAccountService { +export class ConnectedAccountRepository { constructor( private readonly workspaceDataSourceService: WorkspaceDataSourceService, ) {} diff --git a/packages/twenty-server/src/modules/connected-account/repositories/connected-account/connected-account.module.ts b/packages/twenty-server/src/modules/connected-account/repositories/connected-account/connected-account.module.ts deleted file mode 100644 index 736d2e303c31..000000000000 --- a/packages/twenty-server/src/modules/connected-account/repositories/connected-account/connected-account.module.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { ConnectedAccountService } from 'src/modules/connected-account/repositories/connected-account/connected-account.service'; -import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; - -@Module({ - imports: [WorkspaceDataSourceModule], - providers: [ConnectedAccountService], - exports: [ConnectedAccountService], -}) -export class ConnectedAccountModule {} diff --git a/packages/twenty-server/src/modules/connected-account/services/google-api-refresh-access-token/google-api-refresh-access-token.module.ts b/packages/twenty-server/src/modules/connected-account/services/google-api-refresh-access-token/google-api-refresh-access-token.module.ts new file mode 100644 index 000000000000..29db89400d02 --- /dev/null +++ b/packages/twenty-server/src/modules/connected-account/services/google-api-refresh-access-token/google-api-refresh-access-token.module.ts @@ -0,0 +1,14 @@ +import { Module } from '@nestjs/common'; + +import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; +import { GoogleAPIRefreshAccessTokenService } from 'src/modules/connected-account/services/google-api-refresh-access-token/google-api-refresh-access-token.service'; +import { ConnectedAccountObjectMetadata } from 'src/modules/connected-account/standard-objects/connected-account.object-metadata'; + +@Module({ + imports: [ + ObjectMetadataRepositoryModule.forFeature([ConnectedAccountObjectMetadata]), + ], + providers: [GoogleAPIRefreshAccessTokenService], + exports: [GoogleAPIRefreshAccessTokenService], +}) +export class GoogleAPIRefreshAccessTokenModule {} diff --git a/packages/twenty-server/src/modules/connected-account/services/google-apis-refresh-access-token.service.ts b/packages/twenty-server/src/modules/connected-account/services/google-api-refresh-access-token/google-api-refresh-access-token.service.ts similarity index 68% rename from packages/twenty-server/src/modules/connected-account/services/google-apis-refresh-access-token.service.ts rename to packages/twenty-server/src/modules/connected-account/services/google-api-refresh-access-token/google-api-refresh-access-token.service.ts index 88ba8c3d7ee3..284f5b185b3f 100644 --- a/packages/twenty-server/src/modules/connected-account/services/google-apis-refresh-access-token.service.ts +++ b/packages/twenty-server/src/modules/connected-account/services/google-api-refresh-access-token/google-api-refresh-access-token.service.ts @@ -3,20 +3,23 @@ import { Injectable } from '@nestjs/common'; import axios from 'axios'; import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; -import { ConnectedAccountService } from 'src/modules/connected-account/repositories/connected-account/connected-account.service'; +import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; +import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; +import { ConnectedAccountObjectMetadata } from 'src/modules/connected-account/standard-objects/connected-account.object-metadata'; @Injectable() -export class GoogleAPIsRefreshAccessTokenService { +export class GoogleAPIRefreshAccessTokenService { constructor( private readonly environmentService: EnvironmentService, - private readonly connectedAccountService: ConnectedAccountService, + @InjectObjectMetadataRepository(ConnectedAccountObjectMetadata) + private readonly connectedAccountRepository: ConnectedAccountRepository, ) {} async refreshAndSaveAccessToken( workspaceId: string, connectedAccountId: string, ): Promise { - const connectedAccount = await this.connectedAccountService.getById( + const connectedAccount = await this.connectedAccountRepository.getById( connectedAccountId, workspaceId, ); @@ -37,7 +40,7 @@ export class GoogleAPIsRefreshAccessTokenService { const accessToken = await this.refreshAccessToken(refreshToken); - await this.connectedAccountService.updateAccessToken( + await this.connectedAccountRepository.updateAccessToken( accessToken, connectedAccountId, workspaceId, diff --git a/packages/twenty-server/src/modules/messaging/commands/crons/fetch-all-workspaces-messages.job.ts b/packages/twenty-server/src/modules/messaging/commands/crons/fetch-all-workspaces-messages.job.ts index 2867fa1b09d4..d6756626ee45 100644 --- a/packages/twenty-server/src/modules/messaging/commands/crons/fetch-all-workspaces-messages.job.ts +++ b/packages/twenty-server/src/modules/messaging/commands/crons/fetch-all-workspaces-messages.job.ts @@ -7,13 +7,15 @@ import { MessageQueueJob } from 'src/engine/integrations/message-queue/interface import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; -import { ConnectedAccountService } from 'src/modules/connected-account/repositories/connected-account/connected-account.service'; +import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; import { Workspace } from 'src/engine/modules/workspace/workspace.entity'; import { GmailPartialSyncJobData, GmailPartialSyncJob, } from 'src/modules/messaging/jobs/gmail-partial-sync.job'; import { DataSourceEntity } from 'src/engine-metadata/data-source/data-source.entity'; +import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; +import { ConnectedAccountObjectMetadata } from 'src/modules/connected-account/standard-objects/connected-account.object-metadata'; @Injectable() export class FetchAllWorkspacesMessagesJob @@ -28,7 +30,8 @@ export class FetchAllWorkspacesMessagesJob private readonly dataSourceRepository: Repository, @Inject(MessageQueue.messagingQueue) private readonly messageQueueService: MessageQueueService, - private readonly connectedAccountService: ConnectedAccountService, + @InjectObjectMetadataRepository(ConnectedAccountObjectMetadata) + private readonly connectedAccountRepository: ConnectedAccountRepository, ) {} async handle(): Promise { @@ -59,7 +62,7 @@ export class FetchAllWorkspacesMessagesJob private async fetchWorkspaceMessages(workspaceId: string): Promise { try { const connectedAccounts = - await this.connectedAccountService.getAll(workspaceId); + await this.connectedAccountRepository.getAll(workspaceId); for (const connectedAccount of connectedAccounts) { await this.messageQueueService.add( diff --git a/packages/twenty-server/src/modules/messaging/commands/fetch-workspace-messages-commands.module.ts b/packages/twenty-server/src/modules/messaging/commands/fetch-workspace-messages-commands.module.ts index cd0936e1b6fa..c285a6235ecf 100644 --- a/packages/twenty-server/src/modules/messaging/commands/fetch-workspace-messages-commands.module.ts +++ b/packages/twenty-server/src/modules/messaging/commands/fetch-workspace-messages-commands.module.ts @@ -1,21 +1,15 @@ import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; -import { FeatureFlagEntity } from 'src/engine/modules/feature-flag/feature-flag.entity'; -import { TypeORMModule } from 'src/database/typeorm/typeorm.module'; -import { DataSourceModule } from 'src/engine-metadata/data-source/data-source.module'; +import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; +import { ConnectedAccountObjectMetadata } from 'src/modules/connected-account/standard-objects/connected-account.object-metadata'; import { GmailFullSyncCommand } from 'src/modules/messaging/commands/gmail-full-sync.command'; import { GmailPartialSyncCommand } from 'src/modules/messaging/commands/gmail-partial-sync.command'; -import { ConnectedAccountModule } from 'src/modules/connected-account/repositories/connected-account/connected-account.module'; import { StartFetchAllWorkspacesMessagesCronCommand } from 'src/modules/messaging/commands/start-fetch-all-workspaces-messages.cron.command'; import { StopFetchAllWorkspacesMessagesCronCommand } from 'src/modules/messaging/commands/stop-fetch-all-workspaces-messages.cron.command'; @Module({ imports: [ - DataSourceModule, - TypeORMModule, - TypeOrmModule.forFeature([FeatureFlagEntity], 'core'), - ConnectedAccountModule, + ObjectMetadataRepositoryModule.forFeature([ConnectedAccountObjectMetadata]), ], providers: [ GmailFullSyncCommand, diff --git a/packages/twenty-server/src/modules/messaging/commands/gmail-full-sync.command.ts b/packages/twenty-server/src/modules/messaging/commands/gmail-full-sync.command.ts index 375986cb13c0..da47d33266b1 100644 --- a/packages/twenty-server/src/modules/messaging/commands/gmail-full-sync.command.ts +++ b/packages/twenty-server/src/modules/messaging/commands/gmail-full-sync.command.ts @@ -8,7 +8,9 @@ import { GmailFullSyncJobData, GmailFullSyncJob, } from 'src/modules/messaging/jobs/gmail-full-sync.job'; -import { ConnectedAccountService } from 'src/modules/connected-account/repositories/connected-account/connected-account.service'; +import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; +import { ConnectedAccountObjectMetadata } from 'src/modules/connected-account/standard-objects/connected-account.object-metadata'; +import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; interface GmailFullSyncOptions { workspaceId: string; @@ -22,7 +24,8 @@ export class GmailFullSyncCommand extends CommandRunner { constructor( @Inject(MessageQueue.messagingQueue) private readonly messageQueueService: MessageQueueService, - private readonly connectedAccountService: ConnectedAccountService, + @InjectObjectMetadataRepository(ConnectedAccountObjectMetadata) + private readonly connectedAccountRepository: ConnectedAccountRepository, ) { super(); } @@ -47,7 +50,7 @@ export class GmailFullSyncCommand extends CommandRunner { private async fetchWorkspaceMessages(workspaceId: string): Promise { const connectedAccounts = - await this.connectedAccountService.getAll(workspaceId); + await this.connectedAccountRepository.getAll(workspaceId); for (const connectedAccount of connectedAccounts) { await this.messageQueueService.add( diff --git a/packages/twenty-server/src/modules/messaging/commands/gmail-partial-sync.command.ts b/packages/twenty-server/src/modules/messaging/commands/gmail-partial-sync.command.ts index 0511a9ad0b48..36c4dd57c6ea 100644 --- a/packages/twenty-server/src/modules/messaging/commands/gmail-partial-sync.command.ts +++ b/packages/twenty-server/src/modules/messaging/commands/gmail-partial-sync.command.ts @@ -8,7 +8,9 @@ import { GmailPartialSyncJob, GmailPartialSyncJobData, } from 'src/modules/messaging/jobs/gmail-partial-sync.job'; -import { ConnectedAccountService } from 'src/modules/connected-account/repositories/connected-account/connected-account.service'; +import { ConnectedAccountObjectMetadata } from 'src/modules/connected-account/standard-objects/connected-account.object-metadata'; +import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; +import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; interface GmailPartialSyncOptions { workspaceId: string; @@ -22,7 +24,8 @@ export class GmailPartialSyncCommand extends CommandRunner { constructor( @Inject(MessageQueue.messagingQueue) private readonly messageQueueService: MessageQueueService, - private readonly connectedAccountService: ConnectedAccountService, + @InjectObjectMetadataRepository(ConnectedAccountObjectMetadata) + private readonly connectedAccountService: ConnectedAccountRepository, ) { super(); } diff --git a/packages/twenty-server/src/modules/messaging/jobs/create-companies-and-contacts-after-sync.job.ts b/packages/twenty-server/src/modules/messaging/jobs/create-companies-and-contacts-after-sync.job.ts index 650828b45fe0..4908da0a3272 100644 --- a/packages/twenty-server/src/modules/messaging/jobs/create-companies-and-contacts-after-sync.job.ts +++ b/packages/twenty-server/src/modules/messaging/jobs/create-companies-and-contacts-after-sync.job.ts @@ -2,9 +2,13 @@ import { Injectable, Logger } from '@nestjs/common'; import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; +import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; import { CreateCompanyAndContactService } from 'src/modules/connected-account/auto-companies-and-contacts-creation/create-company-and-contact/create-company-and-contact.service'; -import { MessageChannelService } from 'src/modules/messaging/repositories/message-channel/message-channel.service'; -import { MessageParticipantService } from 'src/modules/messaging/repositories/message-participant/message-participant.service'; +import { MessageChannelRepository } from 'src/modules/messaging/repositories/message-channel.repository'; +import { MessageParticipantRepository } from 'src/modules/messaging/repositories/message-participant.repository'; +import { MessageParticipantService } from 'src/modules/messaging/services/message-participant/message-participant.service'; +import { MessageChannelObjectMetadata } from 'src/modules/messaging/standard-objects/message-channel.object-metadata'; +import { MessageParticipantObjectMetadata } from 'src/modules/messaging/standard-objects/message-participant.object-metadata'; export type CreateCompaniesAndContactsAfterSyncJobData = { workspaceId: string; @@ -20,8 +24,11 @@ export class CreateCompaniesAndContactsAfterSyncJob ); constructor( private readonly createCompaniesAndContactsService: CreateCompanyAndContactService, - private readonly messageChannelService: MessageChannelService, + @InjectObjectMetadataRepository(MessageChannelObjectMetadata) + private readonly messageChannelService: MessageChannelRepository, private readonly messageParticipantService: MessageParticipantService, + @InjectObjectMetadataRepository(MessageParticipantObjectMetadata) + private readonly messageParticipantRepository: MessageParticipantRepository, ) {} async handle( @@ -44,7 +51,7 @@ export class CreateCompaniesAndContactsAfterSyncJob } const messageParticipantsWithoutPersonIdAndWorkspaceMemberId = - await this.messageParticipantService.getByMessageChannelIdWithoutPersonIdAndWorkspaceMemberIdAndMessageOutgoing( + await this.messageParticipantRepository.getByMessageChannelIdWithoutPersonIdAndWorkspaceMemberIdAndMessageOutgoing( messageChannelId, workspaceId, ); diff --git a/packages/twenty-server/src/modules/messaging/jobs/gmail-full-sync.job.ts b/packages/twenty-server/src/modules/messaging/jobs/gmail-full-sync.job.ts index c721f1752d0a..7011ded5b50d 100644 --- a/packages/twenty-server/src/modules/messaging/jobs/gmail-full-sync.job.ts +++ b/packages/twenty-server/src/modules/messaging/jobs/gmail-full-sync.job.ts @@ -2,8 +2,8 @@ import { Injectable, Logger } from '@nestjs/common'; import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; -import { GoogleAPIsRefreshAccessTokenService } from 'src/modules/connected-account/services/google-apis-refresh-access-token.service'; -import { GmailFullSyncService } from 'src/modules/messaging/services/gmail-full-sync.service'; +import { GoogleAPIRefreshAccessTokenService } from 'src/modules/connected-account/services/google-api-refresh-access-token/google-api-refresh-access-token.service'; +import { GmailFullSyncService } from 'src/modules/messaging/services/gmail-full-sync/gmail-full-sync.service'; export type GmailFullSyncJobData = { workspaceId: string; @@ -16,7 +16,7 @@ export class GmailFullSyncJob implements MessageQueueJob { private readonly logger = new Logger(GmailFullSyncJob.name); constructor( - private readonly googleAPIsRefreshAccessTokenService: GoogleAPIsRefreshAccessTokenService, + private readonly googleAPIsRefreshAccessTokenService: GoogleAPIRefreshAccessTokenService, private readonly gmailFullSyncService: GmailFullSyncService, ) {} diff --git a/packages/twenty-server/src/modules/messaging/jobs/gmail-partial-sync.job.ts b/packages/twenty-server/src/modules/messaging/jobs/gmail-partial-sync.job.ts index b96ca955f101..478bb33345fc 100644 --- a/packages/twenty-server/src/modules/messaging/jobs/gmail-partial-sync.job.ts +++ b/packages/twenty-server/src/modules/messaging/jobs/gmail-partial-sync.job.ts @@ -2,8 +2,8 @@ import { Injectable, Logger } from '@nestjs/common'; import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; -import { GoogleAPIsRefreshAccessTokenService } from 'src/modules/connected-account/services/google-apis-refresh-access-token.service'; -import { GmailPartialSyncService } from 'src/modules/messaging/services/gmail-partial-sync.service'; +import { GoogleAPIRefreshAccessTokenService } from 'src/modules/connected-account/services/google-api-refresh-access-token/google-api-refresh-access-token.service'; +import { GmailPartialSyncService } from 'src/modules/messaging/services/gmail-partial-sync/gmail-partial-sync.service'; export type GmailPartialSyncJobData = { workspaceId: string; @@ -17,7 +17,7 @@ export class GmailPartialSyncJob private readonly logger = new Logger(GmailPartialSyncJob.name); constructor( - private readonly googleAPIsRefreshAccessTokenService: GoogleAPIsRefreshAccessTokenService, + private readonly googleAPIsRefreshAccessTokenService: GoogleAPIRefreshAccessTokenService, private readonly gmailPartialSyncService: GmailPartialSyncService, ) {} diff --git a/packages/twenty-server/src/modules/messaging/jobs/match-message-participant.job.ts b/packages/twenty-server/src/modules/messaging/jobs/match-message-participant.job.ts index 2b058b7e55de..9eadb5898907 100644 --- a/packages/twenty-server/src/modules/messaging/jobs/match-message-participant.job.ts +++ b/packages/twenty-server/src/modules/messaging/jobs/match-message-participant.job.ts @@ -2,7 +2,9 @@ import { Injectable } from '@nestjs/common'; import { MessageQueueJob } from 'src/engine/integrations/message-queue/interfaces/message-queue-job.interface'; -import { MessageParticipantService } from 'src/modules/messaging/repositories/message-participant/message-participant.service'; +import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; +import { MessageParticipantRepository } from 'src/modules/messaging/repositories/message-participant.repository'; +import { MessageParticipantObjectMetadata } from 'src/modules/messaging/standard-objects/message-participant.object-metadata'; export type MatchMessageParticipantsJobData = { workspaceId: string; @@ -16,28 +18,32 @@ export class MatchMessageParticipantJob implements MessageQueueJob { constructor( - private readonly messageParticipantService: MessageParticipantService, + @InjectObjectMetadataRepository(MessageParticipantObjectMetadata) + private readonly messageParticipantRepository: MessageParticipantRepository, ) {} async handle(data: MatchMessageParticipantsJobData): Promise { const { workspaceId, personId, workspaceMemberId, email } = data; const messageParticipantsToUpdate = - await this.messageParticipantService.getByHandles([email], workspaceId); + await this.messageParticipantRepository.getByHandles( + [email], + workspaceId, + ); const messageParticipantIdsToUpdate = messageParticipantsToUpdate.map( (participant) => participant.id, ); if (personId) { - await this.messageParticipantService.updateParticipantsPersonId( + await this.messageParticipantRepository.updateParticipantsPersonId( messageParticipantIdsToUpdate, personId, workspaceId, ); } if (workspaceMemberId) { - await this.messageParticipantService.updateParticipantsWorkspaceMemberId( + await this.messageParticipantRepository.updateParticipantsWorkspaceMemberId( messageParticipantIdsToUpdate, workspaceMemberId, workspaceId, diff --git a/packages/twenty-server/src/modules/messaging/listeners/messaging-connected-account.listener.ts b/packages/twenty-server/src/modules/messaging/listeners/messaging-connected-account.listener.ts index bb352d612155..f0f2ee0a096c 100644 --- a/packages/twenty-server/src/modules/messaging/listeners/messaging-connected-account.listener.ts +++ b/packages/twenty-server/src/modules/messaging/listeners/messaging-connected-account.listener.ts @@ -1,5 +1,8 @@ import { Injectable, Inject } from '@nestjs/common'; import { OnEvent } from '@nestjs/event-emitter'; +import { InjectRepository } from '@nestjs/typeorm'; + +import { Repository } from 'typeorm'; import { ObjectRecordDeleteEvent } from 'src/engine/integrations/event-emitter/types/object-record-delete.event'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; @@ -13,6 +16,10 @@ import { DeleteConnectedAccountAssociatedMessagingDataJob, } from 'src/modules/messaging/jobs/delete-connected-account-associated-messaging-data.job'; import { ConnectedAccountObjectMetadata } from 'src/modules/connected-account/standard-objects/connected-account.object-metadata'; +import { + FeatureFlagEntity, + FeatureFlagKeys, +} from 'src/engine/modules/feature-flag/feature-flag.entity'; @Injectable() export class MessagingConnectedAccountListener { @@ -21,12 +28,20 @@ export class MessagingConnectedAccountListener { private readonly messageQueueService: MessageQueueService, @Inject(MessageQueue.calendarQueue) private readonly calendarQueueService: MessageQueueService, + @InjectRepository(FeatureFlagEntity, 'core') + private readonly featureFlagRepository: Repository, ) {} @OnEvent('connectedAccount.deleted') - handleDeletedEvent( + async handleDeletedEvent( payload: ObjectRecordDeleteEvent, ) { + const isCalendarEnabled = await this.featureFlagRepository.findOneBy({ + workspaceId: payload.workspaceId, + key: FeatureFlagKeys.IsCalendarEnabled, + value: true, + }); + this.messageQueueService.add( DeleteConnectedAccountAssociatedMessagingDataJob.name, { @@ -35,12 +50,14 @@ export class MessagingConnectedAccountListener { }, ); - this.calendarQueueService.add( - DeleteConnectedAccountAssociatedCalendarDataJob.name, - { - workspaceId: payload.workspaceId, - connectedAccountId: payload.deletedRecord.id, - }, - ); + if (isCalendarEnabled) { + this.calendarQueueService.add( + DeleteConnectedAccountAssociatedCalendarDataJob.name, + { + workspaceId: payload.workspaceId, + connectedAccountId: payload.deletedRecord.id, + }, + ); + } } } diff --git a/packages/twenty-server/src/modules/messaging/messaging.module.ts b/packages/twenty-server/src/modules/messaging/messaging.module.ts index d2da63b31d84..9dd275e9f3d9 100644 --- a/packages/twenty-server/src/modules/messaging/messaging.module.ts +++ b/packages/twenty-server/src/modules/messaging/messaging.module.ts @@ -1,76 +1,19 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; -import { HttpModule } from '@nestjs/axios'; -import { ConnectedAccountModule } from 'src/modules/connected-account/repositories/connected-account/connected-account.module'; -import { MessageChannelMessageAssociationModule } from 'src/modules/messaging/repositories/message-channel-message-association/message-channel-message-assocation.module'; -import { MessageChannelModule } from 'src/modules/messaging/repositories/message-channel/message-channel.module'; -import { MessageThreadModule } from 'src/modules/messaging/repositories/message-thread/message-thread.module'; -import { EnvironmentModule } from 'src/engine/integrations/environment/environment.module'; import { MessagingPersonListener } from 'src/modules/messaging/listeners/messaging-person.listener'; -import { MessageModule } from 'src/modules/messaging/repositories/message/message.module'; -import { GmailClientProvider } from 'src/modules/messaging/services/providers/gmail/gmail-client.provider'; -import { CreateContactService } from 'src/modules/connected-account/auto-companies-and-contacts-creation/create-contact/create-contact.service'; -import { CreateCompanyService } from 'src/modules/connected-account/auto-companies-and-contacts-creation/create-company/create-company.service'; -import { FetchMessagesByBatchesService } from 'src/modules/messaging/services/fetch-messages-by-batches.service'; -import { GmailFullSyncService } from 'src/modules/messaging/services/gmail-full-sync.service'; -import { GmailPartialSyncService } from 'src/modules/messaging/services/gmail-partial-sync.service'; -import { GoogleAPIsRefreshAccessTokenService } from 'src/modules/connected-account/services/google-apis-refresh-access-token.service'; -import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; -import { MessageParticipantModule } from 'src/modules/messaging/repositories/message-participant/message-participant.module'; import { MessagingWorkspaceMemberListener } from 'src/modules/messaging/listeners/messaging-workspace-member.listener'; import { MessagingMessageChannelListener } from 'src/modules/messaging/listeners/messaging-message-channel.listener'; -import { MessageService } from 'src/modules/messaging/repositories/message/message.service'; -import { WorkspaceMemberModule } from 'src/modules/workspace-member/repositories/workspace-member/workspace-member.module'; -import { FeatureFlagEntity } from 'src/engine/modules/feature-flag/feature-flag.entity'; -import { CreateCompaniesAndContactsModule } from 'src/modules/connected-account/auto-companies-and-contacts-creation/create-company-and-contact/create-company-and-contact.module'; -import { CompanyModule } from 'src/modules/messaging/repositories/company/company.module'; -import { PersonModule } from 'src/modules/person/repositories/person/person.module'; -import { SaveMessagesAndCreateContactsService } from 'src/modules/messaging/services/save-messages-and-create-contacts.service'; import { MessagingConnectedAccountListener } from 'src/modules/messaging/listeners/messaging-connected-account.listener'; -import { BlocklistModule } from 'src/modules/connected-account/repositories/blocklist/blocklist.module'; -import { FetchByBatchesService } from 'src/modules/messaging/services/fetch-by-batch.service'; +import { FeatureFlagEntity } from 'src/engine/modules/feature-flag/feature-flag.entity'; @Module({ - imports: [ - EnvironmentModule, - WorkspaceDataSourceModule, - ConnectedAccountModule, - MessageChannelModule, - MessageChannelMessageAssociationModule, - MessageModule, - MessageThreadModule, - MessageParticipantModule, - CreateCompaniesAndContactsModule, - WorkspaceMemberModule, - TypeOrmModule.forFeature([FeatureFlagEntity], 'core'), - CompanyModule, - PersonModule, - BlocklistModule, - HttpModule.register({ - baseURL: 'https://www.googleapis.com/batch/gmail/v1', - }), - ], + imports: [TypeOrmModule.forFeature([FeatureFlagEntity], 'core')], providers: [ - GmailFullSyncService, - GmailPartialSyncService, - FetchMessagesByBatchesService, - GoogleAPIsRefreshAccessTokenService, - GmailClientProvider, - CreateContactService, - CreateCompanyService, MessagingPersonListener, MessagingWorkspaceMemberListener, MessagingMessageChannelListener, - MessageService, - SaveMessagesAndCreateContactsService, MessagingConnectedAccountListener, - FetchByBatchesService, - ], - exports: [ - GmailPartialSyncService, - GmailFullSyncService, - GoogleAPIsRefreshAccessTokenService, - FetchByBatchesService, ], + exports: [], }) export class MessagingModule {} diff --git a/packages/twenty-server/src/modules/messaging/query-hooks/message/message-find-many.pre-query.hook.ts b/packages/twenty-server/src/modules/messaging/query-hooks/message/message-find-many.pre-query.hook.ts index b5fb45c3f869..5824e536b6cf 100644 --- a/packages/twenty-server/src/modules/messaging/query-hooks/message/message-find-many.pre-query.hook.ts +++ b/packages/twenty-server/src/modules/messaging/query-hooks/message/message-find-many.pre-query.hook.ts @@ -10,18 +10,29 @@ import { groupBy } from 'lodash'; import { WorkspacePreQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/interfaces/workspace-pre-query-hook.interface'; import { FindManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; -import { MessageChannelMessageAssociationService } from 'src/modules/messaging/repositories/message-channel-message-association/message-channel-message-association.service'; -import { MessageChannelService } from 'src/modules/messaging/repositories/message-channel/message-channel.service'; -import { ConnectedAccountService } from 'src/modules/connected-account/repositories/connected-account/connected-account.service'; -import { WorkspaceMemberService } from 'src/modules/workspace-member/repositories/workspace-member/workspace-member.service'; +import { MessageChannelMessageAssociationRepository } from 'src/modules/messaging/repositories/message-channel-message-association.repository'; +import { MessageChannelRepository } from 'src/modules/messaging/repositories/message-channel.repository'; +import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; +import { WorkspaceMemberRepository } from 'src/modules/workspace-member/repositories/workspace-member.repository'; +import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; +import { ConnectedAccountObjectMetadata } from 'src/modules/connected-account/standard-objects/connected-account.object-metadata'; +import { MessageChannelObjectMetadata } from 'src/modules/messaging/standard-objects/message-channel.object-metadata'; +import { MessageChannelMessageAssociationObjectMetadata } from 'src/modules/messaging/standard-objects/message-channel-message-association.object-metadata'; +import { WorkspaceMemberObjectMetadata } from 'src/modules/workspace-member/standard-objects/workspace-member.object-metadata'; @Injectable() export class MessageFindManyPreQueryHook implements WorkspacePreQueryHook { constructor( - private readonly messageChannelMessageAssociationService: MessageChannelMessageAssociationService, - private readonly messageChannelService: MessageChannelService, - private readonly connectedAccountService: ConnectedAccountService, - private readonly workspaceMemberService: WorkspaceMemberService, + @InjectObjectMetadataRepository( + MessageChannelMessageAssociationObjectMetadata, + ) + private readonly messageChannelMessageAssociationService: MessageChannelMessageAssociationRepository, + @InjectObjectMetadataRepository(MessageChannelObjectMetadata) + private readonly messageChannelService: MessageChannelRepository, + @InjectObjectMetadataRepository(ConnectedAccountObjectMetadata) + private readonly connectedAccountRepository: ConnectedAccountRepository, + @InjectObjectMetadataRepository(WorkspaceMemberObjectMetadata) + private readonly workspaceMemberService: WorkspaceMemberRepository, ) {} async execute( @@ -75,7 +86,7 @@ export class MessageFindManyPreQueryHook implements WorkspacePreQueryHook { await this.workspaceMemberService.getByIdOrFail(userId, workspaceId); const messageChannelsConnectedAccounts = - await this.connectedAccountService.getByIds( + await this.connectedAccountRepository.getByIds( messageChannels.map((channel) => channel.connectedAccountId), workspaceId, ); diff --git a/packages/twenty-server/src/modules/messaging/query-hooks/messaging-query-hook.module.ts b/packages/twenty-server/src/modules/messaging/query-hooks/messaging-query-hook.module.ts index 0b47c48ff9f2..2570a7f2bc63 100644 --- a/packages/twenty-server/src/modules/messaging/query-hooks/messaging-query-hook.module.ts +++ b/packages/twenty-server/src/modules/messaging/query-hooks/messaging-query-hook.module.ts @@ -2,17 +2,20 @@ import { Module } from '@nestjs/common'; import { MessageFindManyPreQueryHook } from 'src/modules/messaging/query-hooks/message/message-find-many.pre-query.hook'; import { MessageFindOnePreQueryHook } from 'src/modules/messaging/query-hooks/message/message-find-one.pre-query-hook'; -import { ConnectedAccountModule } from 'src/modules/connected-account/repositories/connected-account/connected-account.module'; -import { MessageChannelMessageAssociationModule } from 'src/modules/messaging/repositories/message-channel-message-association/message-channel-message-assocation.module'; -import { MessageChannelModule } from 'src/modules/messaging/repositories/message-channel/message-channel.module'; -import { WorkspaceMemberModule } from 'src/modules/workspace-member/repositories/workspace-member/workspace-member.module'; +import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; +import { WorkspaceMemberObjectMetadata } from 'src/modules/workspace-member/standard-objects/workspace-member.object-metadata'; +import { MessageChannelMessageAssociationObjectMetadata } from 'src/modules/messaging/standard-objects/message-channel-message-association.object-metadata'; +import { ConnectedAccountObjectMetadata } from 'src/modules/connected-account/standard-objects/connected-account.object-metadata'; +import { MessageChannelObjectMetadata } from 'src/modules/messaging/standard-objects/message-channel.object-metadata'; @Module({ imports: [ - MessageChannelMessageAssociationModule, - MessageChannelModule, - ConnectedAccountModule, - WorkspaceMemberModule, + ObjectMetadataRepositoryModule.forFeature([ + MessageChannelMessageAssociationObjectMetadata, + MessageChannelObjectMetadata, + ConnectedAccountObjectMetadata, + WorkspaceMemberObjectMetadata, + ]), ], providers: [ { diff --git a/packages/twenty-server/src/modules/messaging/repositories/company/company.module.ts b/packages/twenty-server/src/modules/messaging/repositories/company/company.module.ts deleted file mode 100644 index 61460d6bf876..000000000000 --- a/packages/twenty-server/src/modules/messaging/repositories/company/company.module.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { CompanyService } from 'src/modules/messaging/repositories/company/company.service'; -import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; - -// TODO: Move outside of the messaging module -@Module({ - imports: [WorkspaceDataSourceModule], - providers: [CompanyService], - exports: [CompanyService], -}) -export class CompanyModule {} diff --git a/packages/twenty-server/src/modules/messaging/repositories/message-channel-message-association/message-channel-message-association.service.ts b/packages/twenty-server/src/modules/messaging/repositories/message-channel-message-association.repository.ts similarity index 88% rename from packages/twenty-server/src/modules/messaging/repositories/message-channel-message-association/message-channel-message-association.service.ts rename to packages/twenty-server/src/modules/messaging/repositories/message-channel-message-association.repository.ts index 17454e6027bb..eb5f283e2d07 100644 --- a/packages/twenty-server/src/modules/messaging/repositories/message-channel-message-association/message-channel-message-association.service.ts +++ b/packages/twenty-server/src/modules/messaging/repositories/message-channel-message-association.repository.ts @@ -7,7 +7,7 @@ import { MessageChannelMessageAssociationObjectMetadata } from 'src/modules/mess import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; @Injectable() -export class MessageChannelMessageAssociationService { +export class MessageChannelMessageAssociationRepository { constructor( private readonly workspaceDataSourceService: WorkspaceDataSourceService, ) {} @@ -192,4 +192,30 @@ export class MessageChannelMessageAssociationService { transactionManager, ); } + + public async insert( + messageChannelId: string, + messageId: string, + messageExternalId: string, + messageThreadId: string, + messageThreadExternalId: string, + workspaceId: string, + transactionManager?: EntityManager, + ): Promise { + const dataSourceSchema = + this.workspaceDataSourceService.getSchemaName(workspaceId); + + await this.workspaceDataSourceService.executeRawQuery( + `INSERT INTO ${dataSourceSchema}."messageChannelMessageAssociation" ("messageChannelId", "messageId", "messageExternalId", "messageThreadId", "messageThreadExternalId") VALUES ($1, $2, $3, $4, $5)`, + [ + messageChannelId, + messageId, + messageExternalId, + messageThreadId, + messageThreadExternalId, + ], + workspaceId, + transactionManager, + ); + } } diff --git a/packages/twenty-server/src/modules/messaging/repositories/message-channel-message-association/message-channel-message-assocation.module.ts b/packages/twenty-server/src/modules/messaging/repositories/message-channel-message-association/message-channel-message-assocation.module.ts deleted file mode 100644 index 7c9f4de8f5a4..000000000000 --- a/packages/twenty-server/src/modules/messaging/repositories/message-channel-message-association/message-channel-message-assocation.module.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { MessageChannelMessageAssociationService } from 'src/modules/messaging/repositories/message-channel-message-association/message-channel-message-association.service'; -import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; - -@Module({ - imports: [WorkspaceDataSourceModule], - providers: [MessageChannelMessageAssociationService], - exports: [MessageChannelMessageAssociationService], -}) -export class MessageChannelMessageAssociationModule {} diff --git a/packages/twenty-server/src/modules/messaging/repositories/message-channel/message-channel.service.ts b/packages/twenty-server/src/modules/messaging/repositories/message-channel.repository.ts similarity index 98% rename from packages/twenty-server/src/modules/messaging/repositories/message-channel/message-channel.service.ts rename to packages/twenty-server/src/modules/messaging/repositories/message-channel.repository.ts index 71712ea67887..59c0ddab7b87 100644 --- a/packages/twenty-server/src/modules/messaging/repositories/message-channel/message-channel.service.ts +++ b/packages/twenty-server/src/modules/messaging/repositories/message-channel.repository.ts @@ -7,7 +7,7 @@ import { MessageChannelObjectMetadata } from 'src/modules/messaging/standard-obj import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; @Injectable() -export class MessageChannelService { +export class MessageChannelRepository { constructor( private readonly workspaceDataSourceService: WorkspaceDataSourceService, ) {} diff --git a/packages/twenty-server/src/modules/messaging/repositories/message-channel/message-channel.module.ts b/packages/twenty-server/src/modules/messaging/repositories/message-channel/message-channel.module.ts deleted file mode 100644 index 90661ee6b506..000000000000 --- a/packages/twenty-server/src/modules/messaging/repositories/message-channel/message-channel.module.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { MessageChannelService } from 'src/modules/messaging/repositories/message-channel/message-channel.service'; -import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; - -@Module({ - imports: [WorkspaceDataSourceModule], - providers: [MessageChannelService], - exports: [MessageChannelService], -}) -export class MessageChannelModule {} diff --git a/packages/twenty-server/src/modules/messaging/repositories/message-participant/message-participant.service.ts b/packages/twenty-server/src/modules/messaging/repositories/message-participant.repository.ts similarity index 82% rename from packages/twenty-server/src/modules/messaging/repositories/message-participant/message-participant.service.ts rename to packages/twenty-server/src/modules/messaging/repositories/message-participant.repository.ts index 71b9635f6481..839cf63ca295 100644 --- a/packages/twenty-server/src/modules/messaging/repositories/message-participant/message-participant.service.ts +++ b/packages/twenty-server/src/modules/messaging/repositories/message-participant.repository.ts @@ -9,13 +9,11 @@ import { ParticipantWithId, ParticipantWithMessageId, } from 'src/modules/messaging/types/gmail-message'; -import { PersonService } from 'src/modules/person/repositories/person/person.service'; @Injectable() -export class MessageParticipantService { +export class MessageParticipantRepository { constructor( private readonly workspaceDataSourceService: WorkspaceDataSourceService, - private readonly personService: PersonService, ) {} public async getByHandles( @@ -195,45 +193,4 @@ export class MessageParticipantService { transactionManager, ); } - - public async updateMessageParticipantsAfterPeopleCreation( - participants: ParticipantWithId[], - workspaceId: string, - transactionManager?: EntityManager, - ): Promise { - if (!participants) return; - - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - const handles = participants.map((participant) => participant.handle); - - const participantPersonIds = await this.personService.getByEmails( - handles, - workspaceId, - transactionManager, - ); - - const messageParticipantsToUpdate = participants.map((participant) => [ - participant.id, - participantPersonIds.find( - (e: { id: string; email: string }) => e.email === participant.handle, - )?.id, - ]); - - if (messageParticipantsToUpdate.length === 0) return; - - const valuesString = messageParticipantsToUpdate - .map((_, index) => `($${index * 2 + 1}::uuid, $${index * 2 + 2}::uuid)`) - .join(', '); - - 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"`, - messageParticipantsToUpdate.flat(), - workspaceId, - transactionManager, - ); - } } diff --git a/packages/twenty-server/src/modules/messaging/repositories/message-participant/message-participant.module.ts b/packages/twenty-server/src/modules/messaging/repositories/message-participant/message-participant.module.ts deleted file mode 100644 index e8754fe547b1..000000000000 --- a/packages/twenty-server/src/modules/messaging/repositories/message-participant/message-participant.module.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { MessageParticipantService } from 'src/modules/messaging/repositories/message-participant/message-participant.service'; -import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; -import { PersonModule } from 'src/modules/person/repositories/person/person.module'; - -@Module({ - imports: [WorkspaceDataSourceModule, PersonModule], - providers: [MessageParticipantService], - exports: [MessageParticipantService], -}) -export class MessageParticipantModule {} diff --git a/packages/twenty-server/src/modules/messaging/repositories/message-thread.repository.ts b/packages/twenty-server/src/modules/messaging/repositories/message-thread.repository.ts new file mode 100644 index 000000000000..bf0e9d7c90af --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/repositories/message-thread.repository.ts @@ -0,0 +1,67 @@ +import { Injectable } from '@nestjs/common'; + +import { EntityManager } from 'typeorm'; + +import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; + +@Injectable() +export class MessageThreadRepository { + constructor( + private readonly workspaceDataSourceService: WorkspaceDataSourceService, + ) {} + + public async getOrphanThreadIdsPaginated( + limit: number, + offset: number, + workspaceId: string, + transactionManager?: EntityManager, + ): Promise { + const dataSourceSchema = + this.workspaceDataSourceService.getSchemaName(workspaceId); + + const orphanThreads = await this.workspaceDataSourceService.executeRawQuery( + `SELECT mt.id + FROM ${dataSourceSchema}."messageThread" mt + LEFT JOIN ${dataSourceSchema}."message" m ON mt.id = m."messageThreadId" + WHERE m."messageThreadId" IS NULL + LIMIT $1 OFFSET $2`, + [limit, offset], + workspaceId, + transactionManager, + ); + + return orphanThreads.map(({ id }) => id); + } + + public async deleteByIds( + messageThreadIds: string[], + workspaceId: string, + transactionManager?: EntityManager, + ): Promise { + const dataSourceSchema = + this.workspaceDataSourceService.getSchemaName(workspaceId); + + await this.workspaceDataSourceService.executeRawQuery( + `DELETE FROM ${dataSourceSchema}."messageThread" WHERE id = ANY($1)`, + [messageThreadIds], + workspaceId, + transactionManager, + ); + } + + public async insert( + messageThreadId: string, + workspaceId: string, + transactionManager?: EntityManager, + ): Promise { + const dataSourceSchema = + this.workspaceDataSourceService.getSchemaName(workspaceId); + + await this.workspaceDataSourceService.executeRawQuery( + `INSERT INTO ${dataSourceSchema}."messageThread" (id) VALUES ($1)`, + [messageThreadId], + workspaceId, + transactionManager, + ); + } +} diff --git a/packages/twenty-server/src/modules/messaging/repositories/message-thread/message-thread.module.ts b/packages/twenty-server/src/modules/messaging/repositories/message-thread/message-thread.module.ts deleted file mode 100644 index d08c2358bacc..000000000000 --- a/packages/twenty-server/src/modules/messaging/repositories/message-thread/message-thread.module.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Module, forwardRef } from '@nestjs/common'; - -import { MessageChannelMessageAssociationModule } from 'src/modules/messaging/repositories/message-channel-message-association/message-channel-message-assocation.module'; -import { MessageThreadService } from 'src/modules/messaging/repositories/message-thread/message-thread.service'; -import { MessageModule } from 'src/modules/messaging/repositories/message/message.module'; -import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; - -@Module({ - imports: [ - WorkspaceDataSourceModule, - MessageChannelMessageAssociationModule, - forwardRef(() => MessageModule), - ], - providers: [MessageThreadService], - exports: [MessageThreadService], -}) -export class MessageThreadModule {} diff --git a/packages/twenty-server/src/modules/messaging/repositories/message-thread/message-thread.service.ts b/packages/twenty-server/src/modules/messaging/repositories/message-thread/message-thread.service.ts deleted file mode 100644 index b4196940964c..000000000000 --- a/packages/twenty-server/src/modules/messaging/repositories/message-thread/message-thread.service.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { Inject, Injectable, forwardRef } from '@nestjs/common'; - -import { EntityManager } from 'typeorm'; -import { v4 } from 'uuid'; - -import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; -import { DataSourceEntity } from 'src/engine-metadata/data-source/data-source.entity'; -import { MessageChannelMessageAssociationService } from 'src/modules/messaging/repositories/message-channel-message-association/message-channel-message-association.service'; -import { MessageService } from 'src/modules/messaging/repositories/message/message.service'; - -@Injectable() -export class MessageThreadService { - constructor( - private readonly messageChannelMessageAssociationService: MessageChannelMessageAssociationService, - private readonly workspaceDataSourceService: WorkspaceDataSourceService, - @Inject(forwardRef(() => MessageService)) - private readonly messageService: MessageService, - ) {} - - public async getOrphanThreadIdsPaginated( - limit: number, - offset: number, - workspaceId: string, - transactionManager?: EntityManager, - ): Promise { - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - const orphanThreads = await this.workspaceDataSourceService.executeRawQuery( - `SELECT mt.id - FROM ${dataSourceSchema}."messageThread" mt - LEFT JOIN ${dataSourceSchema}."message" m ON mt.id = m."messageThreadId" - WHERE m."messageThreadId" IS NULL - LIMIT $1 OFFSET $2`, - [limit, offset], - workspaceId, - transactionManager, - ); - - return orphanThreads.map(({ id }) => id); - } - - public async deleteByIds( - messageThreadIds: string[], - workspaceId: string, - transactionManager?: EntityManager, - ): Promise { - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - await this.workspaceDataSourceService.executeRawQuery( - `DELETE FROM ${dataSourceSchema}."messageThread" WHERE id = ANY($1)`, - [messageThreadIds], - workspaceId, - transactionManager, - ); - } - - public async saveMessageThreadOrReturnExistingMessageThread( - headerMessageId: string, - messageThreadExternalId: string, - dataSourceMetadata: DataSourceEntity, - workspaceId: string, - manager: EntityManager, - ) { - // Check if message thread already exists via threadExternalId - const existingMessageChannelMessageAssociationByMessageThreadExternalId = - await this.messageChannelMessageAssociationService.getFirstByMessageThreadExternalId( - messageThreadExternalId, - workspaceId, - manager, - ); - - const existingMessageThread = - existingMessageChannelMessageAssociationByMessageThreadExternalId?.messageThreadId; - - if (existingMessageThread) { - return Promise.resolve(existingMessageThread); - } - - // Check if message thread already exists via existing message headerMessageId - const existingMessageWithSameHeaderMessageId = - await this.messageService.getFirstOrNullByHeaderMessageId( - headerMessageId, - workspaceId, - manager, - ); - - if (existingMessageWithSameHeaderMessageId) { - return Promise.resolve( - existingMessageWithSameHeaderMessageId.messageThreadId, - ); - } - - // If message thread does not exist, create new message thread - const newMessageThreadId = v4(); - - await manager.query( - `INSERT INTO ${dataSourceMetadata.schema}."messageThread" ("id") VALUES ($1)`, - [newMessageThreadId], - ); - - return Promise.resolve(newMessageThreadId); - } -} diff --git a/packages/twenty-server/src/modules/messaging/repositories/message.repository.ts b/packages/twenty-server/src/modules/messaging/repositories/message.repository.ts new file mode 100644 index 000000000000..b884f4458ee0 --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/repositories/message.repository.ts @@ -0,0 +1,138 @@ +import { Injectable } from '@nestjs/common'; + +import { EntityManager } from 'typeorm'; + +import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; +import { MessageObjectMetadata } from 'src/modules/messaging/standard-objects/message.object-metadata'; +import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; + +@Injectable() +export class MessageRepository { + constructor( + private readonly workspaceDataSourceService: WorkspaceDataSourceService, + ) {} + + public async getNonAssociatedMessageIdsPaginated( + limit: number, + offset: number, + workspaceId: string, + transactionManager?: EntityManager, + ): Promise { + const dataSourceSchema = + this.workspaceDataSourceService.getSchemaName(workspaceId); + + const nonAssociatedMessages = + await this.workspaceDataSourceService.executeRawQuery( + `SELECT m.id FROM ${dataSourceSchema}."message" m + LEFT JOIN ${dataSourceSchema}."messageChannelMessageAssociation" mcma + ON m.id = mcma."messageId" + WHERE mcma.id IS NULL + LIMIT $1 OFFSET $2`, + [limit, offset], + workspaceId, + transactionManager, + ); + + return nonAssociatedMessages.map(({ id }) => id); + } + + public async getFirstOrNullByHeaderMessageId( + headerMessageId: string, + workspaceId: string, + transactionManager?: EntityManager, + ): Promise | null> { + const dataSourceSchema = + this.workspaceDataSourceService.getSchemaName(workspaceId); + + const messages = await this.workspaceDataSourceService.executeRawQuery( + `SELECT * FROM ${dataSourceSchema}."message" WHERE "headerMessageId" = $1 LIMIT 1`, + [headerMessageId], + workspaceId, + transactionManager, + ); + + if (!messages || messages.length === 0) { + return null; + } + + return messages[0]; + } + + public async getByIds( + messageIds: string[], + workspaceId: string, + transactionManager?: EntityManager, + ): Promise[]> { + const dataSourceSchema = + this.workspaceDataSourceService.getSchemaName(workspaceId); + + return await this.workspaceDataSourceService.executeRawQuery( + `SELECT * FROM ${dataSourceSchema}."message" WHERE "id" = ANY($1)`, + [messageIds], + workspaceId, + transactionManager, + ); + } + + public async deleteByIds( + messageIds: string[], + workspaceId: string, + transactionManager?: EntityManager, + ): Promise { + const dataSourceSchema = + this.workspaceDataSourceService.getSchemaName(workspaceId); + + await this.workspaceDataSourceService.executeRawQuery( + `DELETE FROM ${dataSourceSchema}."message" WHERE "id" = ANY($1)`, + [messageIds], + workspaceId, + transactionManager, + ); + } + + public async getByMessageThreadIds( + messageThreadIds: string[], + workspaceId: string, + transactionManager?: EntityManager, + ): Promise[]> { + const dataSourceSchema = + this.workspaceDataSourceService.getSchemaName(workspaceId); + + return await this.workspaceDataSourceService.executeRawQuery( + `SELECT * FROM ${dataSourceSchema}."message" WHERE "messageThreadId" = ANY($1)`, + [messageThreadIds], + workspaceId, + transactionManager, + ); + } + + public async insert( + id: string, + headerMessageId: string, + subject: string, + receivedAt: Date, + messageDirection: string, + messageThreadId: string, + text: string, + workspaceId: string, + transactionManager?: EntityManager, + ): Promise { + const dataSourceSchema = + this.workspaceDataSourceService.getSchemaName(workspaceId); + + await this.workspaceDataSourceService.executeRawQuery( + `INSERT INTO ${dataSourceSchema}."message" ("id", "headerMessageId", "subject", "receivedAt", "direction", "messageThreadId", "text") VALUES ($1, $2, $3, $4, $5, $6, $7)`, + [ + id, + headerMessageId, + subject, + receivedAt, + messageDirection, + messageThreadId, + text, + ], + workspaceId, + transactionManager, + ); + } +} diff --git a/packages/twenty-server/src/modules/messaging/repositories/message/message.module.ts b/packages/twenty-server/src/modules/messaging/repositories/message/message.module.ts deleted file mode 100644 index d6cbaab6d81b..000000000000 --- a/packages/twenty-server/src/modules/messaging/repositories/message/message.module.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Module, forwardRef } from '@nestjs/common'; - -import { MessageChannelModule } from 'src/modules/messaging/repositories/message-channel/message-channel.module'; -import { MessageChannelMessageAssociationModule } from 'src/modules/messaging/repositories/message-channel-message-association/message-channel-message-assocation.module'; -import { MessageParticipantModule } from 'src/modules/messaging/repositories/message-participant/message-participant.module'; -import { MessageThreadModule } from 'src/modules/messaging/repositories/message-thread/message-thread.module'; -import { MessageService } from 'src/modules/messaging/repositories/message/message.service'; -import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; -import { CreateCompaniesAndContactsModule } from 'src/modules/connected-account/auto-companies-and-contacts-creation/create-company-and-contact/create-company-and-contact.module'; - -@Module({ - imports: [ - WorkspaceDataSourceModule, - forwardRef(() => MessageThreadModule), - MessageParticipantModule, - MessageChannelMessageAssociationModule, - MessageChannelModule, - CreateCompaniesAndContactsModule, - ], - providers: [MessageService], - exports: [MessageService], -}) -export class MessageModule {} diff --git a/packages/twenty-server/src/modules/messaging/services/fetch-by-batch/fetch-by-batch.module.ts b/packages/twenty-server/src/modules/messaging/services/fetch-by-batch/fetch-by-batch.module.ts new file mode 100644 index 000000000000..0535c95caf87 --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/services/fetch-by-batch/fetch-by-batch.module.ts @@ -0,0 +1,15 @@ +import { HttpModule } from '@nestjs/axios'; +import { Module } from '@nestjs/common'; + +import { FetchByBatchesService } from 'src/modules/messaging/services/fetch-by-batch/fetch-by-batch.service'; + +@Module({ + imports: [ + HttpModule.register({ + baseURL: 'https://www.googleapis.com/batch/gmail/v1', + }), + ], + providers: [FetchByBatchesService], + exports: [FetchByBatchesService], +}) +export class FetchByBatchModule {} diff --git a/packages/twenty-server/src/modules/messaging/services/fetch-by-batch.service.ts b/packages/twenty-server/src/modules/messaging/services/fetch-by-batch/fetch-by-batch.service.ts similarity index 100% rename from packages/twenty-server/src/modules/messaging/services/fetch-by-batch.service.ts rename to packages/twenty-server/src/modules/messaging/services/fetch-by-batch/fetch-by-batch.service.ts diff --git a/packages/twenty-server/src/modules/messaging/services/fetch-messages-by-batches/fetch-messages-by-batches.module.ts b/packages/twenty-server/src/modules/messaging/services/fetch-messages-by-batches/fetch-messages-by-batches.module.ts new file mode 100644 index 000000000000..9bcb913718b6 --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/services/fetch-messages-by-batches/fetch-messages-by-batches.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; + +import { FetchByBatchModule } from 'src/modules/messaging/services/fetch-by-batch/fetch-by-batch.module'; +import { FetchMessagesByBatchesService } from 'src/modules/messaging/services/fetch-messages-by-batches/fetch-messages-by-batches.service'; + +@Module({ + imports: [FetchByBatchModule], + providers: [FetchMessagesByBatchesService], + exports: [FetchMessagesByBatchesService], +}) +export class FetchMessagesByBatchesModule {} diff --git a/packages/twenty-server/src/modules/messaging/services/fetch-messages-by-batches.service.ts b/packages/twenty-server/src/modules/messaging/services/fetch-messages-by-batches/fetch-messages-by-batches.service.ts similarity index 99% rename from packages/twenty-server/src/modules/messaging/services/fetch-messages-by-batches.service.ts rename to packages/twenty-server/src/modules/messaging/services/fetch-messages-by-batches/fetch-messages-by-batches.service.ts index 9fb5badbf3bd..63b2b2e0d7bb 100644 --- a/packages/twenty-server/src/modules/messaging/services/fetch-messages-by-batches.service.ts +++ b/packages/twenty-server/src/modules/messaging/services/fetch-messages-by-batches/fetch-messages-by-batches.service.ts @@ -7,7 +7,7 @@ import planer from 'planer'; import { GmailMessage } from 'src/modules/messaging/types/gmail-message'; import { MessageQuery } from 'src/modules/messaging/types/message-or-thread-query'; import { GmailMessageParsedResponse } from 'src/modules/messaging/types/gmail-message-parsed-response'; -import { FetchByBatchesService } from 'src/modules/messaging/services/fetch-by-batch.service'; +import { FetchByBatchesService } from 'src/modules/messaging/services/fetch-by-batch/fetch-by-batch.service'; import { formatAddressObjectAsParticipants } from 'src/modules/messaging/services/utils/format-address-object-as-participants.util'; @Injectable() diff --git a/packages/twenty-server/src/modules/messaging/services/gmail-full-sync/gmail-full-sync.module.ts b/packages/twenty-server/src/modules/messaging/services/gmail-full-sync/gmail-full-sync.module.ts new file mode 100644 index 000000000000..b9a12f9c2947 --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/services/gmail-full-sync/gmail-full-sync.module.ts @@ -0,0 +1,31 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { FeatureFlagEntity } from 'src/engine/modules/feature-flag/feature-flag.entity'; +import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; +import { BlocklistObjectMetadata } from 'src/modules/connected-account/standard-objects/blocklist.object-metadata'; +import { ConnectedAccountObjectMetadata } from 'src/modules/connected-account/standard-objects/connected-account.object-metadata'; +import { FetchMessagesByBatchesModule } from 'src/modules/messaging/services/fetch-messages-by-batches/fetch-messages-by-batches.module'; +import { GmailFullSyncService } from 'src/modules/messaging/services/gmail-full-sync/gmail-full-sync.service'; +import { MessagingProvidersModule } from 'src/modules/messaging/services/providers/messaging-providers.module'; +import { SaveMessagesAndCreateContactsModule } from 'src/modules/messaging/services/save-message-and-create-contact/save-message-and-create-contacts.module'; +import { MessageChannelMessageAssociationObjectMetadata } from 'src/modules/messaging/standard-objects/message-channel-message-association.object-metadata'; +import { MessageChannelObjectMetadata } from 'src/modules/messaging/standard-objects/message-channel.object-metadata'; + +@Module({ + imports: [ + MessagingProvidersModule, + FetchMessagesByBatchesModule, + ObjectMetadataRepositoryModule.forFeature([ + ConnectedAccountObjectMetadata, + MessageChannelObjectMetadata, + MessageChannelMessageAssociationObjectMetadata, + BlocklistObjectMetadata, + ]), + SaveMessagesAndCreateContactsModule, + TypeOrmModule.forFeature([FeatureFlagEntity], 'core'), + ], + providers: [GmailFullSyncService], + exports: [GmailFullSyncService], +}) +export class GmailFullSyncModule {} diff --git a/packages/twenty-server/src/modules/messaging/services/gmail-full-sync.service.ts b/packages/twenty-server/src/modules/messaging/services/gmail-full-sync/gmail-full-sync.service.ts similarity index 76% rename from packages/twenty-server/src/modules/messaging/services/gmail-full-sync.service.ts rename to packages/twenty-server/src/modules/messaging/services/gmail-full-sync/gmail-full-sync.service.ts index cfcfe9171ff6..61cd34f11a9f 100644 --- a/packages/twenty-server/src/modules/messaging/services/gmail-full-sync.service.ts +++ b/packages/twenty-server/src/modules/messaging/services/gmail-full-sync/gmail-full-sync.service.ts @@ -3,7 +3,7 @@ import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; -import { FetchMessagesByBatchesService } from 'src/modules/messaging/services/fetch-messages-by-batches.service'; +import { FetchMessagesByBatchesService } from 'src/modules/messaging/services/fetch-messages-by-batches/fetch-messages-by-batches.service'; import { GmailClientProvider } from 'src/modules/messaging/services/providers/gmail/gmail-client.provider'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; @@ -11,17 +11,22 @@ import { GmailFullSyncJobData, GmailFullSyncJob, } from 'src/modules/messaging/jobs/gmail-full-sync.job'; -import { ConnectedAccountService } from 'src/modules/connected-account/repositories/connected-account/connected-account.service'; -import { MessageChannelService } from 'src/modules/messaging/repositories/message-channel/message-channel.service'; -import { MessageChannelMessageAssociationService } from 'src/modules/messaging/repositories/message-channel-message-association/message-channel-message-association.service'; +import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; +import { MessageChannelRepository } from 'src/modules/messaging/repositories/message-channel.repository'; +import { MessageChannelMessageAssociationRepository } from 'src/modules/messaging/repositories/message-channel-message-association.repository'; import { createQueriesFromMessageIds } from 'src/modules/messaging/utils/create-queries-from-message-ids.util'; import { gmailSearchFilterExcludeEmails } from 'src/modules/messaging/utils/gmail-search-filter.util'; -import { BlocklistService } from 'src/modules/connected-account/repositories/blocklist/blocklist.service'; -import { SaveMessagesAndCreateContactsService } from 'src/modules/messaging/services/save-messages-and-create-contacts.service'; +import { BlocklistRepository } from 'src/modules/connected-account/repositories/blocklist.repository'; +import { SaveMessagesAndCreateContactsService } from 'src/modules/messaging/services/save-message-and-create-contact/save-messages-and-create-contacts.service'; import { FeatureFlagEntity, FeatureFlagKeys, } from 'src/engine/modules/feature-flag/feature-flag.entity'; +import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; +import { ConnectedAccountObjectMetadata } from 'src/modules/connected-account/standard-objects/connected-account.object-metadata'; +import { MessageChannelObjectMetadata } from 'src/modules/messaging/standard-objects/message-channel.object-metadata'; +import { MessageChannelMessageAssociationObjectMetadata } from 'src/modules/messaging/standard-objects/message-channel-message-association.object-metadata'; +import { BlocklistObjectMetadata } from 'src/modules/connected-account/standard-objects/blocklist.object-metadata'; @Injectable() export class GmailFullSyncService { @@ -32,10 +37,16 @@ export class GmailFullSyncService { private readonly fetchMessagesByBatchesService: FetchMessagesByBatchesService, @Inject(MessageQueue.messagingQueue) private readonly messageQueueService: MessageQueueService, - private readonly connectedAccountService: ConnectedAccountService, - private readonly messageChannelService: MessageChannelService, - private readonly messageChannelMessageAssociationService: MessageChannelMessageAssociationService, - private readonly blocklistService: BlocklistService, + @InjectObjectMetadataRepository(ConnectedAccountObjectMetadata) + private readonly connectedAccountRepository: ConnectedAccountRepository, + @InjectObjectMetadataRepository(MessageChannelObjectMetadata) + private readonly messageChannelRepository: MessageChannelRepository, + @InjectObjectMetadataRepository( + MessageChannelMessageAssociationObjectMetadata, + ) + private readonly messageChannelMessageAssociationRepository: MessageChannelMessageAssociationRepository, + @InjectObjectMetadataRepository(BlocklistObjectMetadata) + private readonly blocklistRepository: BlocklistRepository, private readonly saveMessagesAndCreateContactsService: SaveMessagesAndCreateContactsService, @InjectRepository(FeatureFlagEntity, 'core') private readonly featureFlagRepository: Repository, @@ -46,7 +57,7 @@ export class GmailFullSyncService { connectedAccountId: string, nextPageToken?: string, ): Promise { - const connectedAccount = await this.connectedAccountService.getById( + const connectedAccount = await this.connectedAccountRepository.getById( connectedAccountId, workspaceId, ); @@ -70,7 +81,7 @@ export class GmailFullSyncService { } const gmailMessageChannel = - await this.messageChannelService.getFirstByConnectedAccountId( + await this.messageChannelRepository.getFirstByConnectedAccountId( connectedAccountId, workspaceId, ); @@ -99,7 +110,7 @@ export class GmailFullSyncService { isBlocklistEnabledFeatureFlag && isBlocklistEnabledFeatureFlag.value; const blocklist = isBlocklistEnabled - ? await this.blocklistService.getByWorkspaceMemberId( + ? await this.blocklistRepository.getByWorkspaceMemberId( workspaceMemberId, workspaceId, ) @@ -140,7 +151,7 @@ export class GmailFullSyncService { startTime = Date.now(); const existingMessageChannelMessageAssociations = - await this.messageChannelMessageAssociationService.getByMessageExternalIdsAndMessageChannelId( + await this.messageChannelMessageAssociationRepository.getByMessageExternalIdsAndMessageChannelId( messageExternalIds, gmailMessageChannelId, workspaceId, @@ -221,7 +232,7 @@ export class GmailFullSyncService { startTime = Date.now(); - await this.connectedAccountService.updateLastSyncHistoryIdIfHigher( + await this.connectedAccountRepository.updateLastSyncHistoryIdIfHigher( historyId, connectedAccount.id, workspaceId, diff --git a/packages/twenty-server/src/modules/messaging/services/gmail-partial-sync/gmail-partial-sync.module.ts b/packages/twenty-server/src/modules/messaging/services/gmail-partial-sync/gmail-partial-sync.module.ts new file mode 100644 index 000000000000..744e70295bf4 --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/services/gmail-partial-sync/gmail-partial-sync.module.ts @@ -0,0 +1,31 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { FeatureFlagEntity } from 'src/engine/modules/feature-flag/feature-flag.entity'; +import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; +import { BlocklistObjectMetadata } from 'src/modules/connected-account/standard-objects/blocklist.object-metadata'; +import { ConnectedAccountObjectMetadata } from 'src/modules/connected-account/standard-objects/connected-account.object-metadata'; +import { FetchMessagesByBatchesModule } from 'src/modules/messaging/services/fetch-messages-by-batches/fetch-messages-by-batches.module'; +import { GmailPartialSyncService } from 'src/modules/messaging/services/gmail-partial-sync/gmail-partial-sync.service'; +import { MessageModule } from 'src/modules/messaging/services/message/message.module'; +import { MessagingProvidersModule } from 'src/modules/messaging/services/providers/messaging-providers.module'; +import { SaveMessagesAndCreateContactsModule } from 'src/modules/messaging/services/save-message-and-create-contact/save-message-and-create-contacts.module'; +import { MessageChannelObjectMetadata } from 'src/modules/messaging/standard-objects/message-channel.object-metadata'; + +@Module({ + imports: [ + MessagingProvidersModule, + FetchMessagesByBatchesModule, + ObjectMetadataRepositoryModule.forFeature([ + ConnectedAccountObjectMetadata, + MessageChannelObjectMetadata, + BlocklistObjectMetadata, + ]), + MessageModule, + SaveMessagesAndCreateContactsModule, + TypeOrmModule.forFeature([FeatureFlagEntity], 'core'), + ], + providers: [GmailPartialSyncService], + exports: [GmailPartialSyncService], +}) +export class GmailPartialSyncModule {} diff --git a/packages/twenty-server/src/modules/messaging/services/gmail-partial-sync.service.ts b/packages/twenty-server/src/modules/messaging/services/gmail-partial-sync/gmail-partial-sync.service.ts similarity index 86% rename from packages/twenty-server/src/modules/messaging/services/gmail-partial-sync.service.ts rename to packages/twenty-server/src/modules/messaging/services/gmail-partial-sync/gmail-partial-sync.service.ts index a9698b63cee8..e202fb820d4e 100644 --- a/packages/twenty-server/src/modules/messaging/services/gmail-partial-sync.service.ts +++ b/packages/twenty-server/src/modules/messaging/services/gmail-partial-sync/gmail-partial-sync.service.ts @@ -4,7 +4,7 @@ import { InjectRepository } from '@nestjs/typeorm'; import { gmail_v1 } from 'googleapis'; import { Repository } from 'typeorm'; -import { FetchMessagesByBatchesService } from 'src/modules/messaging/services/fetch-messages-by-batches.service'; +import { FetchMessagesByBatchesService } from 'src/modules/messaging/services/fetch-messages-by-batches/fetch-messages-by-batches.service'; import { GmailClientProvider } from 'src/modules/messaging/services/providers/gmail/gmail-client.provider'; import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; @@ -12,18 +12,22 @@ import { GmailFullSyncJob, GmailFullSyncJobData, } from 'src/modules/messaging/jobs/gmail-full-sync.job'; -import { ConnectedAccountService } from 'src/modules/connected-account/repositories/connected-account/connected-account.service'; -import { MessageChannelService } from 'src/modules/messaging/repositories/message-channel/message-channel.service'; -import { MessageService } from 'src/modules/messaging/repositories/message/message.service'; +import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository'; +import { MessageChannelRepository } from 'src/modules/messaging/repositories/message-channel.repository'; import { createQueriesFromMessageIds } from 'src/modules/messaging/utils/create-queries-from-message-ids.util'; import { GmailMessage } from 'src/modules/messaging/types/gmail-message'; import { isPersonEmail } from 'src/modules/messaging/utils/is-person-email.util'; -import { BlocklistService } from 'src/modules/connected-account/repositories/blocklist/blocklist.service'; -import { SaveMessagesAndCreateContactsService } from 'src/modules/messaging/services/save-messages-and-create-contacts.service'; +import { BlocklistRepository } from 'src/modules/connected-account/repositories/blocklist.repository'; +import { SaveMessagesAndCreateContactsService } from 'src/modules/messaging/services/save-message-and-create-contact/save-messages-and-create-contacts.service'; import { FeatureFlagEntity, FeatureFlagKeys, } from 'src/engine/modules/feature-flag/feature-flag.entity'; +import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; +import { ConnectedAccountObjectMetadata } from 'src/modules/connected-account/standard-objects/connected-account.object-metadata'; +import { MessageChannelObjectMetadata } from 'src/modules/messaging/standard-objects/message-channel.object-metadata'; +import { BlocklistObjectMetadata } from 'src/modules/connected-account/standard-objects/blocklist.object-metadata'; +import { MessageService } from 'src/modules/messaging/services/message/message.service'; @Injectable() export class GmailPartialSyncService { @@ -34,10 +38,13 @@ export class GmailPartialSyncService { private readonly fetchMessagesByBatchesService: FetchMessagesByBatchesService, @Inject(MessageQueue.messagingQueue) private readonly messageQueueService: MessageQueueService, - private readonly connectedAccountService: ConnectedAccountService, - private readonly messageChannelService: MessageChannelService, + @InjectObjectMetadataRepository(ConnectedAccountObjectMetadata) + private readonly connectedAccountRepository: ConnectedAccountRepository, + @InjectObjectMetadataRepository(MessageChannelObjectMetadata) + private readonly messageChannelRepository: MessageChannelRepository, private readonly messageService: MessageService, - private readonly blocklistService: BlocklistService, + @InjectObjectMetadataRepository(BlocklistObjectMetadata) + private readonly blocklistRepository: BlocklistRepository, private readonly saveMessagesAndCreateContactsService: SaveMessagesAndCreateContactsService, @InjectRepository(FeatureFlagEntity, 'core') private readonly featureFlagRepository: Repository, @@ -48,7 +55,7 @@ export class GmailPartialSyncService { connectedAccountId: string, maxResults = 500, ): Promise { - const connectedAccount = await this.connectedAccountService.getById( + const connectedAccount = await this.connectedAccountRepository.getById( connectedAccountId, workspaceId, ); @@ -103,7 +110,7 @@ export class GmailPartialSyncService { `gmail partial-sync for workspace ${workspaceId} and account ${connectedAccountId}: invalid lastSyncHistoryId, falling back to full sync.`, ); - await this.connectedAccountService.deleteHistoryId( + await this.connectedAccountRepository.deleteHistoryId( connectedAccountId, workspaceId, ); @@ -143,7 +150,7 @@ export class GmailPartialSyncService { } const gmailMessageChannel = - await this.messageChannelService.getFirstByConnectedAccountId( + await this.messageChannelRepository.getFirstByConnectedAccountId( connectedAccountId, workspaceId, ); @@ -183,7 +190,7 @@ export class GmailPartialSyncService { isBlocklistEnabledFeatureFlag && isBlocklistEnabledFeatureFlag.value; const blocklist = isBlocklistEnabled - ? await this.blocklistService.getByWorkspaceMemberId( + ? await this.blocklistRepository.getByWorkspaceMemberId( connectedAccount.accountOwnerId, workspaceId, ) @@ -251,7 +258,7 @@ export class GmailPartialSyncService { } startTime = Date.now(); - await this.connectedAccountService.updateLastSyncHistoryId( + await this.connectedAccountRepository.updateLastSyncHistoryId( historyId, connectedAccount.id, workspaceId, diff --git a/packages/twenty-server/src/modules/messaging/services/message-participant/message-participant.module.ts b/packages/twenty-server/src/modules/messaging/services/message-participant/message-participant.module.ts new file mode 100644 index 000000000000..9491cb305961 --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/services/message-participant/message-participant.module.ts @@ -0,0 +1,16 @@ +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 { MessageParticipantService } from 'src/modules/messaging/services/message-participant/message-participant.service'; +import { PersonObjectMetadata } from 'src/modules/person/standard-objects/person.object-metadata'; + +@Module({ + imports: [ + WorkspaceDataSourceModule, + ObjectMetadataRepositoryModule.forFeature([PersonObjectMetadata]), + ], + providers: [MessageParticipantService], + exports: [MessageParticipantService], +}) +export class MessageParticipantModule {} diff --git a/packages/twenty-server/src/modules/messaging/services/message-participant/message-participant.service.ts b/packages/twenty-server/src/modules/messaging/services/message-participant/message-participant.service.ts new file mode 100644 index 000000000000..7219051817e1 --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/services/message-participant/message-participant.service.ts @@ -0,0 +1,59 @@ +import { Injectable } from '@nestjs/common'; + +import { EntityManager } from 'typeorm'; + +import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; +import { ParticipantWithId } from 'src/modules/messaging/types/gmail-message'; +import { PersonRepository } from 'src/modules/person/repositories/person.repository'; +import { PersonObjectMetadata } from 'src/modules/person/standard-objects/person.object-metadata'; +import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; + +@Injectable() +export class MessageParticipantService { + constructor( + private readonly workspaceDataSourceService: WorkspaceDataSourceService, + @InjectObjectMetadataRepository(PersonObjectMetadata) + private readonly personRepository: PersonRepository, + ) {} + + public async updateMessageParticipantsAfterPeopleCreation( + participants: ParticipantWithId[], + workspaceId: string, + transactionManager?: EntityManager, + ): Promise { + 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) => [ + participant.id, + participantPersonIds.find( + (e: { id: string; email: string }) => e.email === participant.handle, + )?.id, + ]); + + if (messageParticipantsToUpdate.length === 0) return; + + const valuesString = messageParticipantsToUpdate + .map((_, index) => `($${index * 2 + 1}::uuid, $${index * 2 + 2}::uuid)`) + .join(', '); + + 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"`, + messageParticipantsToUpdate.flat(), + workspaceId, + transactionManager, + ); + } +} diff --git a/packages/twenty-server/src/modules/messaging/services/message-thread/message-thread.module.ts b/packages/twenty-server/src/modules/messaging/services/message-thread/message-thread.module.ts new file mode 100644 index 000000000000..c06f474db6b8 --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/services/message-thread/message-thread.module.ts @@ -0,0 +1,20 @@ +import { Module } from '@nestjs/common'; + +import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; +import { MessageThreadService } from 'src/modules/messaging/services/message-thread/message-thread.service'; +import { MessageChannelMessageAssociationObjectMetadata } from 'src/modules/messaging/standard-objects/message-channel-message-association.object-metadata'; +import { MessageThreadObjectMetadata } from 'src/modules/messaging/standard-objects/message-thread.object-metadata'; +import { MessageObjectMetadata } from 'src/modules/messaging/standard-objects/message.object-metadata'; + +@Module({ + imports: [ + ObjectMetadataRepositoryModule.forFeature([ + MessageChannelMessageAssociationObjectMetadata, + MessageObjectMetadata, + MessageThreadObjectMetadata, + ]), + ], + providers: [MessageThreadService], + exports: [MessageThreadService], +}) +export class MessageThreadModule {} diff --git a/packages/twenty-server/src/modules/messaging/services/message-thread/message-thread.service.ts b/packages/twenty-server/src/modules/messaging/services/message-thread/message-thread.service.ts new file mode 100644 index 000000000000..01fa411a3f99 --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/services/message-thread/message-thread.service.ts @@ -0,0 +1,73 @@ +import { Injectable } from '@nestjs/common'; + +import { EntityManager } from 'typeorm'; +import { v4 } from 'uuid'; + +import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; +import { MessageChannelMessageAssociationRepository } from 'src/modules/messaging/repositories/message-channel-message-association.repository'; +import { MessageRepository } from 'src/modules/messaging/repositories/message.repository'; +import { MessageChannelMessageAssociationObjectMetadata } from 'src/modules/messaging/standard-objects/message-channel-message-association.object-metadata'; +import { MessageThreadObjectMetadata } from 'src/modules/messaging/standard-objects/message-thread.object-metadata'; +import { MessageThreadRepository } from 'src/modules/messaging/repositories/message-thread.repository'; +import { MessageObjectMetadata } from 'src/modules/messaging/standard-objects/message.object-metadata'; + +@Injectable() +export class MessageThreadService { + constructor( + @InjectObjectMetadataRepository( + MessageChannelMessageAssociationObjectMetadata, + ) + private readonly messageChannelMessageAssociationRepository: MessageChannelMessageAssociationRepository, + @InjectObjectMetadataRepository(MessageObjectMetadata) + private readonly messageRepository: MessageRepository, + @InjectObjectMetadataRepository(MessageThreadObjectMetadata) + private readonly messageThreadRepository: MessageThreadRepository, + ) {} + + public async saveMessageThreadOrReturnExistingMessageThread( + headerMessageId: string, + messageThreadExternalId: string, + workspaceId: string, + manager: EntityManager, + ) { + // Check if message thread already exists via threadExternalId + const existingMessageChannelMessageAssociationByMessageThreadExternalId = + await this.messageChannelMessageAssociationRepository.getFirstByMessageThreadExternalId( + messageThreadExternalId, + workspaceId, + manager, + ); + + const existingMessageThread = + existingMessageChannelMessageAssociationByMessageThreadExternalId?.messageThreadId; + + if (existingMessageThread) { + return Promise.resolve(existingMessageThread); + } + + // Check if message thread already exists via existing message headerMessageId + const existingMessageWithSameHeaderMessageId = + await this.messageRepository.getFirstOrNullByHeaderMessageId( + headerMessageId, + workspaceId, + manager, + ); + + if (existingMessageWithSameHeaderMessageId) { + return Promise.resolve( + existingMessageWithSameHeaderMessageId.messageThreadId, + ); + } + + // If message thread does not exist, create new message thread + const newMessageThreadId = v4(); + + await this.messageThreadRepository.insert( + newMessageThreadId, + workspaceId, + manager, + ); + + return Promise.resolve(newMessageThreadId); + } +} diff --git a/packages/twenty-server/src/modules/messaging/services/message/message.module.ts b/packages/twenty-server/src/modules/messaging/services/message/message.module.ts new file mode 100644 index 000000000000..9a2bb8abd7e4 --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/services/message/message.module.ts @@ -0,0 +1,26 @@ +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 { MessageThreadModule } from 'src/modules/messaging/services/message-thread/message-thread.module'; +import { MessageService } from 'src/modules/messaging/services/message/message.service'; +import { MessageChannelMessageAssociationObjectMetadata } from 'src/modules/messaging/standard-objects/message-channel-message-association.object-metadata'; +import { MessageChannelObjectMetadata } from 'src/modules/messaging/standard-objects/message-channel.object-metadata'; +import { MessageThreadObjectMetadata } from 'src/modules/messaging/standard-objects/message-thread.object-metadata'; +import { MessageObjectMetadata } from 'src/modules/messaging/standard-objects/message.object-metadata'; + +@Module({ + imports: [ + WorkspaceDataSourceModule, + ObjectMetadataRepositoryModule.forFeature([ + MessageChannelMessageAssociationObjectMetadata, + MessageObjectMetadata, + MessageChannelObjectMetadata, + MessageThreadObjectMetadata, + ]), + MessageThreadModule, + ], + providers: [MessageService], + exports: [MessageService], +}) +export class MessageModule {} diff --git a/packages/twenty-server/src/modules/messaging/repositories/message/message.service.ts b/packages/twenty-server/src/modules/messaging/services/message/message.service.ts similarity index 56% rename from packages/twenty-server/src/modules/messaging/repositories/message/message.service.ts rename to packages/twenty-server/src/modules/messaging/services/message/message.service.ts index 1dd039ac146f..7832ecefe17e 100644 --- a/packages/twenty-server/src/modules/messaging/repositories/message/message.service.ts +++ b/packages/twenty-server/src/modules/messaging/services/message/message.service.ts @@ -1,17 +1,23 @@ -import { Inject, Injectable, Logger, forwardRef } from '@nestjs/common'; +import { Injectable, Logger } from '@nestjs/common'; import { DataSource, EntityManager } from 'typeorm'; import { v4 } from 'uuid'; -import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; -import { MessageObjectMetadata } from 'src/modules/messaging/standard-objects/message.object-metadata'; -import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; import { DataSourceEntity } from 'src/engine-metadata/data-source/data-source.entity'; -import { GmailMessage } from 'src/modules/messaging/types/gmail-message'; +import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; +import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; import { ConnectedAccountObjectMetadata } from 'src/modules/connected-account/standard-objects/connected-account.object-metadata'; -import { MessageChannelMessageAssociationService } from 'src/modules/messaging/repositories/message-channel-message-association/message-channel-message-association.service'; -import { MessageThreadService } from 'src/modules/messaging/repositories/message-thread/message-thread.service'; -import { MessageChannelService } from 'src/modules/messaging/repositories/message-channel/message-channel.service'; +import { MessageChannelMessageAssociationRepository } from 'src/modules/messaging/repositories/message-channel-message-association.repository'; +import { MessageRepository } from 'src/modules/messaging/repositories/message.repository'; +import { MessageChannelMessageAssociationObjectMetadata } from 'src/modules/messaging/standard-objects/message-channel-message-association.object-metadata'; +import { MessageObjectMetadata } from 'src/modules/messaging/standard-objects/message.object-metadata'; +import { GmailMessage } from 'src/modules/messaging/types/gmail-message'; +import { MessageChannelObjectMetadata } from 'src/modules/messaging/standard-objects/message-channel.object-metadata'; +import { MessageChannelRepository } from 'src/modules/messaging/repositories/message-channel.repository'; +import { MessageThreadService } from 'src/modules/messaging/services/message-thread/message-thread.service'; +import { MessageThreadObjectMetadata } from 'src/modules/messaging/standard-objects/message-thread.object-metadata'; +import { MessageThreadRepository } from 'src/modules/messaging/repositories/message-thread.repository'; +import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; @Injectable() export class MessageService { @@ -19,106 +25,19 @@ export class MessageService { constructor( private readonly workspaceDataSourceService: WorkspaceDataSourceService, - private readonly messageChannelMessageAssociationService: MessageChannelMessageAssociationService, - @Inject(forwardRef(() => MessageThreadService)) + @InjectObjectMetadataRepository( + MessageChannelMessageAssociationObjectMetadata, + ) + private readonly messageChannelMessageAssociationRepository: MessageChannelMessageAssociationRepository, + @InjectObjectMetadataRepository(MessageObjectMetadata) + private readonly messageRepository: MessageRepository, + @InjectObjectMetadataRepository(MessageChannelObjectMetadata) + private readonly messageChannelRepository: MessageChannelRepository, + @InjectObjectMetadataRepository(MessageThreadObjectMetadata) + private readonly messageThreadRepository: MessageThreadRepository, private readonly messageThreadService: MessageThreadService, - private readonly messageChannelService: MessageChannelService, ) {} - public async getNonAssociatedMessageIdsPaginated( - limit: number, - offset: number, - workspaceId: string, - transactionManager?: EntityManager, - ): Promise { - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - const nonAssociatedMessages = - await this.workspaceDataSourceService.executeRawQuery( - `SELECT m.id FROM ${dataSourceSchema}."message" m - LEFT JOIN ${dataSourceSchema}."messageChannelMessageAssociation" mcma - ON m.id = mcma."messageId" - WHERE mcma.id IS NULL - LIMIT $1 OFFSET $2`, - [limit, offset], - workspaceId, - transactionManager, - ); - - return nonAssociatedMessages.map(({ id }) => id); - } - - public async getFirstOrNullByHeaderMessageId( - headerMessageId: string, - workspaceId: string, - transactionManager?: EntityManager, - ): Promise | null> { - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - const messages = await this.workspaceDataSourceService.executeRawQuery( - `SELECT * FROM ${dataSourceSchema}."message" WHERE "headerMessageId" = $1 LIMIT 1`, - [headerMessageId], - workspaceId, - transactionManager, - ); - - if (!messages || messages.length === 0) { - return null; - } - - return messages[0]; - } - - public async getByIds( - messageIds: string[], - workspaceId: string, - transactionManager?: EntityManager, - ): Promise[]> { - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - return await this.workspaceDataSourceService.executeRawQuery( - `SELECT * FROM ${dataSourceSchema}."message" WHERE "id" = ANY($1)`, - [messageIds], - workspaceId, - transactionManager, - ); - } - - public async deleteByIds( - messageIds: string[], - workspaceId: string, - transactionManager?: EntityManager, - ): Promise { - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - await this.workspaceDataSourceService.executeRawQuery( - `DELETE FROM ${dataSourceSchema}."message" WHERE "id" = ANY($1)`, - [messageIds], - workspaceId, - transactionManager, - ); - } - - public async getByMessageThreadIds( - messageThreadIds: string[], - workspaceId: string, - transactionManager?: EntityManager, - ): Promise[]> { - const dataSourceSchema = - this.workspaceDataSourceService.getSchemaName(workspaceId); - - return await this.workspaceDataSourceService.executeRawQuery( - `SELECT * FROM ${dataSourceSchema}."message" WHERE "messageThreadId" = ANY($1)`, - [messageThreadIds], - workspaceId, - transactionManager, - ); - } - public async saveMessages( messages: GmailMessage[], dataSourceMetadata: DataSourceEntity, @@ -140,7 +59,7 @@ export class MessageService { await workspaceDataSource?.transaction( async (manager: EntityManager) => { const gmailMessageChannel = - await this.messageChannelService.getByIds( + await this.messageChannelRepository.getByIds( [gmailMessageChannelId], workspaceId, manager, @@ -157,7 +76,7 @@ export class MessageService { } const existingMessageChannelMessageAssociationsCount = - await this.messageChannelMessageAssociationService.countByMessageExternalIdsAndMessageChannelId( + await this.messageChannelMessageAssociationRepository.countByMessageExternalIdsAndMessageChannelId( [message.externalId], gmailMessageChannelId, workspaceId, @@ -173,7 +92,6 @@ export class MessageService { await this.messageThreadService.saveMessageThreadOrReturnExistingMessageThread( message.headerMessageId, message.messageThreadExternalId, - dataSourceMetadata, workspaceId, manager, ); @@ -193,15 +111,14 @@ export class MessageService { savedOrExistingMessageId, ); - await manager.query( - `INSERT INTO ${dataSourceMetadata.schema}."messageChannelMessageAssociation" ("messageChannelId", "messageId", "messageExternalId", "messageThreadId", "messageThreadExternalId") VALUES ($1, $2, $3, $4, $5)`, - [ - gmailMessageChannelId, - savedOrExistingMessageId, - message.externalId, - savedOrExistingMessageThreadId, - message.messageThreadExternalId, - ], + await this.messageChannelMessageAssociationRepository.insert( + gmailMessageChannelId, + savedOrExistingMessageId, + message.externalId, + savedOrExistingMessageThreadId, + message.messageThreadExternalId, + workspaceId, + manager, ); }, ); @@ -223,10 +140,11 @@ export class MessageService { workspaceId: string, manager: EntityManager, ): Promise { - const existingMessage = await this.getFirstOrNullByHeaderMessageId( - message.headerMessageId, - workspaceId, - ); + const existingMessage = + await this.messageRepository.getFirstOrNullByHeaderMessageId( + message.headerMessageId, + workspaceId, + ); const existingMessageId = existingMessage?.id; if (existingMessageId) { @@ -240,17 +158,16 @@ export class MessageService { const receivedAt = new Date(parseInt(message.internalDate)); - await manager.query( - `INSERT INTO ${dataSourceMetadata.schema}."message" ("id", "headerMessageId", "subject", "receivedAt", "direction", "messageThreadId", "text") VALUES ($1, $2, $3, $4, $5, $6, $7)`, - [ - newMessageId, - message.headerMessageId, - message.subject, - receivedAt, - messageDirection, - messageThreadId, - message.text, - ], + await this.messageRepository.insert( + newMessageId, + message.headerMessageId, + message.subject, + receivedAt, + messageDirection, + messageThreadId, + message.text, + workspaceId, + manager, ); return Promise.resolve(newMessageId); @@ -268,7 +185,7 @@ export class MessageService { await workspaceDataSource?.transaction(async (manager: EntityManager) => { const messageChannelMessageAssociationsToDelete = - await this.messageChannelMessageAssociationService.getByMessageExternalIdsAndMessageChannelId( + await this.messageChannelMessageAssociationRepository.getByMessageExternalIdsAndMessageChannelId( messagesDeletedMessageExternalIds, gmailMessageChannelId, workspaceId, @@ -281,7 +198,7 @@ export class MessageService { messageChannelMessageAssociationToDelete.id, ); - await this.messageChannelMessageAssociationService.deleteByIds( + await this.messageChannelMessageAssociationRepository.deleteByIds( messageChannelMessageAssociationIdsToDeleteIds, workspaceId, manager, @@ -294,7 +211,7 @@ export class MessageService { ); const messageChannelMessageAssociationByMessageIds = - await this.messageChannelMessageAssociationService.getByMessageIds( + await this.messageChannelMessageAssociationRepository.getByMessageIds( messageIdsFromMessageChannelMessageAssociationsToDelete, workspaceId, manager, @@ -314,7 +231,11 @@ export class MessageService { ), ); - await this.deleteByIds(messageIdsToDelete, workspaceId, manager); + await this.messageRepository.deleteByIds( + messageIdsToDelete, + workspaceId, + manager, + ); const messageThreadIdsFromMessageChannelMessageAssociationsToDelete = messageChannelMessageAssociationsToDelete.map( @@ -322,11 +243,12 @@ export class MessageService { messageChannelMessageAssociationToDelete.messageThreadId, ); - const messagesByThreadIds = await this.getByMessageThreadIds( - messageThreadIdsFromMessageChannelMessageAssociationsToDelete, - workspaceId, - manager, - ); + const messagesByThreadIds = + await this.messageRepository.getByMessageThreadIds( + messageThreadIdsFromMessageChannelMessageAssociationsToDelete, + workspaceId, + manager, + ); const threadIdsToDelete = messageThreadIdsFromMessageChannelMessageAssociationsToDelete.filter( @@ -336,7 +258,7 @@ export class MessageService { ), ); - await this.messageThreadService.deleteByIds( + await this.messageThreadRepository.deleteByIds( threadIdsToDelete, workspaceId, manager, diff --git a/packages/twenty-server/src/modules/messaging/services/save-message-and-create-contact/save-message-and-create-contacts.module.ts b/packages/twenty-server/src/modules/messaging/services/save-message-and-create-contact/save-message-and-create-contacts.module.ts new file mode 100644 index 000000000000..6f727a3f4fec --- /dev/null +++ b/packages/twenty-server/src/modules/messaging/services/save-message-and-create-contact/save-message-and-create-contacts.module.ts @@ -0,0 +1,26 @@ +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 { CreateCompaniesAndContactsModule } from 'src/modules/connected-account/auto-companies-and-contacts-creation/create-company-and-contact/create-company-and-contact.module'; +import { MessageParticipantModule } from 'src/modules/messaging/services/message-participant/message-participant.module'; +import { MessageModule } from 'src/modules/messaging/services/message/message.module'; +import { SaveMessagesAndCreateContactsService } from 'src/modules/messaging/services/save-message-and-create-contact/save-messages-and-create-contacts.service'; +import { MessageChannelObjectMetadata } from 'src/modules/messaging/standard-objects/message-channel.object-metadata'; +import { MessageParticipantObjectMetadata } from 'src/modules/messaging/standard-objects/message-participant.object-metadata'; + +@Module({ + imports: [ + MessageModule, + ObjectMetadataRepositoryModule.forFeature([ + MessageChannelObjectMetadata, + MessageParticipantObjectMetadata, + ]), + CreateCompaniesAndContactsModule, + MessageParticipantModule, + WorkspaceDataSourceModule, + ], + providers: [SaveMessagesAndCreateContactsService], + exports: [SaveMessagesAndCreateContactsService], +}) +export class SaveMessagesAndCreateContactsModule {} diff --git a/packages/twenty-server/src/modules/messaging/services/save-messages-and-create-contacts.service.ts b/packages/twenty-server/src/modules/messaging/services/save-message-and-create-contact/save-messages-and-create-contacts.service.ts similarity index 81% rename from packages/twenty-server/src/modules/messaging/services/save-messages-and-create-contacts.service.ts rename to packages/twenty-server/src/modules/messaging/services/save-message-and-create-contact/save-messages-and-create-contacts.service.ts index 87669c8cfe9b..cd18e83aaee1 100644 --- a/packages/twenty-server/src/modules/messaging/services/save-messages-and-create-contacts.service.ts +++ b/packages/twenty-server/src/modules/messaging/services/save-message-and-create-contact/save-messages-and-create-contacts.service.ts @@ -2,9 +2,8 @@ import { Injectable, Logger } from '@nestjs/common'; import { EntityManager } from 'typeorm'; -import { MessageChannelService } from 'src/modules/messaging/repositories/message-channel/message-channel.service'; -import { MessageParticipantService } from 'src/modules/messaging/repositories/message-participant/message-participant.service'; -import { MessageService } from 'src/modules/messaging/repositories/message/message.service'; +import { MessageChannelRepository } from 'src/modules/messaging/repositories/message-channel.repository'; +import { MessageParticipantRepository } from 'src/modules/messaging/repositories/message-participant.repository'; import { CreateCompanyAndContactService } from 'src/modules/connected-account/auto-companies-and-contacts-creation/create-company-and-contact/create-company-and-contact.service'; import { GmailMessage, @@ -13,6 +12,11 @@ import { import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; import { ConnectedAccountObjectMetadata } from 'src/modules/connected-account/standard-objects/connected-account.object-metadata'; import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; +import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; +import { MessageChannelObjectMetadata } from 'src/modules/messaging/standard-objects/message-channel.object-metadata'; +import { MessageService } from 'src/modules/messaging/services/message/message.service'; +import { MessageParticipantObjectMetadata } from 'src/modules/messaging/standard-objects/message-participant.object-metadata'; +import { MessageParticipantService } from 'src/modules/messaging/services/message-participant/message-participant.service'; @Injectable() export class SaveMessagesAndCreateContactsService { @@ -22,7 +26,10 @@ export class SaveMessagesAndCreateContactsService { constructor( private readonly messageService: MessageService, - private readonly messageChannelService: MessageChannelService, + @InjectObjectMetadataRepository(MessageChannelObjectMetadata) + private readonly messageChannelRepository: MessageChannelRepository, + @InjectObjectMetadataRepository(MessageParticipantObjectMetadata) + private readonly messageParticipantRepository: MessageParticipantRepository, private readonly createCompaniesAndContactsService: CreateCompanyAndContactService, private readonly messageParticipantService: MessageParticipantService, private readonly workspaceDataSourceService: WorkspaceDataSourceService, @@ -60,7 +67,7 @@ export class SaveMessagesAndCreateContactsService { ); const gmailMessageChannel = - await this.messageChannelService.getFirstByConnectedAccountId( + await this.messageChannelRepository.getFirstByConnectedAccountId( connectedAccount.id, workspaceId, ); @@ -111,7 +118,7 @@ export class SaveMessagesAndCreateContactsService { ); const messageParticipantsWithoutPersonIdAndWorkspaceMemberId = - await this.messageParticipantService.getByHandlesWithoutPersonIdAndWorkspaceMemberId( + await this.messageParticipantRepository.getByHandlesWithoutPersonIdAndWorkspaceMemberId( handles, workspaceId, ); @@ -157,7 +164,7 @@ export class SaveMessagesAndCreateContactsService { jobName?: string, ) { try { - await this.messageParticipantService.saveMessageParticipants( + await this.messageParticipantRepository.saveMessageParticipants( participantsWithMessageId, workspaceId, ); diff --git a/packages/twenty-server/src/modules/messaging/services/thread-cleaner/thread-cleaner.module.ts b/packages/twenty-server/src/modules/messaging/services/thread-cleaner/thread-cleaner.module.ts index 722c3b0092bd..33b43ab4360e 100644 --- a/packages/twenty-server/src/modules/messaging/services/thread-cleaner/thread-cleaner.module.ts +++ b/packages/twenty-server/src/modules/messaging/services/thread-cleaner/thread-cleaner.module.ts @@ -1,17 +1,16 @@ import { Module } from '@nestjs/common'; -import { TypeORMModule } from 'src/database/typeorm/typeorm.module'; -import { DataSourceModule } from 'src/engine-metadata/data-source/data-source.module'; -import { MessageThreadModule } from 'src/modules/messaging/repositories/message-thread/message-thread.module'; -import { MessageModule } from 'src/modules/messaging/repositories/message/message.module'; +import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; import { ThreadCleanerService } from 'src/modules/messaging/services/thread-cleaner/thread-cleaner.service'; +import { MessageThreadObjectMetadata } from 'src/modules/messaging/standard-objects/message-thread.object-metadata'; +import { MessageObjectMetadata } from 'src/modules/messaging/standard-objects/message.object-metadata'; @Module({ imports: [ - DataSourceModule, - TypeORMModule, - MessageThreadModule, - MessageModule, + ObjectMetadataRepositoryModule.forFeature([ + MessageObjectMetadata, + MessageThreadObjectMetadata, + ]), ], providers: [ThreadCleanerService], exports: [ThreadCleanerService], diff --git a/packages/twenty-server/src/modules/messaging/services/thread-cleaner/thread-cleaner.service.ts b/packages/twenty-server/src/modules/messaging/services/thread-cleaner/thread-cleaner.service.ts index 3374882b634c..f370674dc762 100644 --- a/packages/twenty-server/src/modules/messaging/services/thread-cleaner/thread-cleaner.service.ts +++ b/packages/twenty-server/src/modules/messaging/services/thread-cleaner/thread-cleaner.service.ts @@ -1,37 +1,40 @@ import { Injectable } from '@nestjs/common'; -import { TypeORMService } from 'src/database/typeorm/typeorm.service'; -import { DataSourceService } from 'src/engine-metadata/data-source/data-source.service'; -import { MessageThreadService } from 'src/modules/messaging/repositories/message-thread/message-thread.service'; -import { MessageService } from 'src/modules/messaging/repositories/message/message.service'; +import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; +import { MessageThreadRepository } from 'src/modules/messaging/repositories/message-thread.repository'; +import { MessageRepository } from 'src/modules/messaging/repositories/message.repository'; import { deleteUsingPagination } from 'src/modules/messaging/services/thread-cleaner/utils/delete-using-pagination.util'; +import { MessageThreadObjectMetadata } from 'src/modules/messaging/standard-objects/message-thread.object-metadata'; +import { MessageObjectMetadata } from 'src/modules/messaging/standard-objects/message.object-metadata'; @Injectable() export class ThreadCleanerService { constructor( - private readonly dataSourceService: DataSourceService, - private readonly typeORMService: TypeORMService, - private readonly messageService: MessageService, - private readonly messageThreadService: MessageThreadService, + @InjectObjectMetadataRepository(MessageObjectMetadata) + private readonly messageRepository: MessageRepository, + @InjectObjectMetadataRepository(MessageThreadObjectMetadata) + private readonly messageThreadRepository: MessageThreadRepository, ) {} public async cleanWorkspaceThreads(workspaceId: string) { await deleteUsingPagination( workspaceId, 500, - this.messageService.getNonAssociatedMessageIdsPaginated.bind( - this.messageService, + this.messageRepository.getNonAssociatedMessageIdsPaginated.bind( + this.messageRepository, ), - this.messageService.deleteByIds.bind(this.messageService), + this.messageRepository.deleteByIds.bind(this.messageRepository), ); await deleteUsingPagination( workspaceId, 500, - this.messageThreadService.getOrphanThreadIdsPaginated.bind( - this.messageThreadService, + this.messageThreadRepository.getOrphanThreadIdsPaginated.bind( + this.messageThreadRepository, + ), + this.messageThreadRepository.deleteByIds.bind( + this.messageThreadRepository, ), - this.messageThreadService.deleteByIds.bind(this.messageThreadService), ); } } diff --git a/packages/twenty-server/src/modules/person/repositories/person/person.service.ts b/packages/twenty-server/src/modules/person/repositories/person.repository.ts similarity index 96% rename from packages/twenty-server/src/modules/person/repositories/person/person.service.ts rename to packages/twenty-server/src/modules/person/repositories/person.repository.ts index 502b12f654b9..656c524fac07 100644 --- a/packages/twenty-server/src/modules/person/repositories/person/person.service.ts +++ b/packages/twenty-server/src/modules/person/repositories/person.repository.ts @@ -6,9 +6,8 @@ import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/work import { ObjectRecord } from 'src/engine/workspace-manager/workspace-sync-metadata/types/object-record'; import { PersonObjectMetadata } from 'src/modules/person/standard-objects/person.object-metadata'; -// TODO: Move outside of the messaging module @Injectable() -export class PersonService { +export class PersonRepository { constructor( private readonly workspaceDataSourceService: WorkspaceDataSourceService, ) {} diff --git a/packages/twenty-server/src/modules/person/repositories/person/person.module.ts b/packages/twenty-server/src/modules/person/repositories/person/person.module.ts deleted file mode 100644 index adf359cf792c..000000000000 --- a/packages/twenty-server/src/modules/person/repositories/person/person.module.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { PersonService } from 'src/modules/person/repositories/person/person.service'; -import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; - -@Module({ - imports: [WorkspaceDataSourceModule], - providers: [PersonService], - exports: [PersonService], -}) -export class PersonModule {} diff --git a/packages/twenty-server/src/modules/workspace-member/repositories/workspace-member/workspace-member.service.ts b/packages/twenty-server/src/modules/workspace-member/repositories/workspace-member.repository.ts similarity index 96% rename from packages/twenty-server/src/modules/workspace-member/repositories/workspace-member/workspace-member.service.ts rename to packages/twenty-server/src/modules/workspace-member/repositories/workspace-member.repository.ts index c5d097285925..f2605eb874b9 100644 --- a/packages/twenty-server/src/modules/workspace-member/repositories/workspace-member/workspace-member.service.ts +++ b/packages/twenty-server/src/modules/workspace-member/repositories/workspace-member.repository.ts @@ -6,9 +6,8 @@ import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/work 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'; -// TODO: Move outside of the messaging module @Injectable() -export class WorkspaceMemberService { +export class WorkspaceMemberRepository { constructor( private readonly workspaceDataSourceService: WorkspaceDataSourceService, ) {} diff --git a/packages/twenty-server/src/modules/workspace-member/repositories/workspace-member/workspace-member.module.ts b/packages/twenty-server/src/modules/workspace-member/repositories/workspace-member/workspace-member.module.ts deleted file mode 100644 index 54465e4132f5..000000000000 --- a/packages/twenty-server/src/modules/workspace-member/repositories/workspace-member/workspace-member.module.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { WorkspaceMemberService } from 'src/modules/workspace-member/repositories/workspace-member/workspace-member.service'; -import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; - -@Module({ - imports: [WorkspaceDataSourceModule], - providers: [WorkspaceMemberService], - exports: [WorkspaceMemberService], -}) -export class WorkspaceMemberModule {}