diff --git a/packages/twenty-server/src/database/commands/data-seed-dev-workspace.command.ts b/packages/twenty-server/src/database/commands/data-seed-dev-workspace.command.ts index 1f724a703..517710899 100644 --- a/packages/twenty-server/src/database/commands/data-seed-dev-workspace.command.ts +++ b/packages/twenty-server/src/database/commands/data-seed-dev-workspace.command.ts @@ -1,7 +1,7 @@ import { Logger } from '@nestjs/common'; import { Command, CommandRunner } from 'nest-commander'; -import { DataSource, EntityManager } from 'typeorm'; +import { DataSource } from 'typeorm'; import { seedCoreSchema } from 'src/database/typeorm-seeds/core'; import { @@ -43,6 +43,7 @@ import { SURVEY_RESULTS_DATA_SEEDS } from 'src/engine/seeder/data-seeds/survey-r import { PETS_METADATA_SEEDS } from 'src/engine/seeder/metadata-seeds/pets-metadata-seeds'; import { SURVEY_RESULTS_METADATA_SEEDS } from 'src/engine/seeder/metadata-seeds/survey-results-metadata-seeds'; import { SeederService } from 'src/engine/seeder/seeder.service'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; import { shouldSeedWorkspaceFavorite } from 'src/engine/utils/should-seed-workspace-favorite'; import { createWorkspaceViews } from 'src/engine/workspace-manager/standard-objects-prefill-data/create-workspace-views'; import { seedViewWithDemoData } from 'src/engine/workspace-manager/standard-objects-prefill-data/seed-view-with-demo-data'; @@ -169,7 +170,7 @@ export class DataSeedWorkspaceCommand extends CommandRunner { dataSourceMetadata: DataSourceEntity, ) { await workspaceDataSource.transaction( - async (entityManager: EntityManager) => { + async (entityManager: WorkspaceEntityManager) => { const { objectMetadataStandardIdToIdMap } = await this.objectMetadataService.getObjectMetadataStandardIdToIdMap( dataSourceMetadata.workspaceId, diff --git a/packages/twenty-server/src/database/typeorm-seeds/workspace/api-key.ts b/packages/twenty-server/src/database/typeorm-seeds/workspace/api-key.ts index 8176b240f..63280be9f 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/workspace/api-key.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/workspace/api-key.ts @@ -1,15 +1,17 @@ -import { EntityManager } from 'typeorm'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; const tableName = 'apiKey'; const API_KEY_ID = '20202020-f401-4d8a-a731-64d007c27bad'; export const seedApiKey = async ( - entityManager: EntityManager, + entityManager: WorkspaceEntityManager, schemaName: string, ) => { await entityManager - .createQueryBuilder() + .createQueryBuilder(undefined, undefined, undefined, { + shouldBypassPermissionChecks: true, + }) .insert() .into(`${schemaName}.${tableName}`, ['id', 'name', 'expiresAt']) .orIgnore() diff --git a/packages/twenty-server/src/database/typeorm-seeds/workspace/calendar-channel-event-association.ts b/packages/twenty-server/src/database/typeorm-seeds/workspace/calendar-channel-event-association.ts index 7e20a6ab5..53e02174b 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/workspace/calendar-channel-event-association.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/workspace/calendar-channel-event-association.ts @@ -1,13 +1,15 @@ -import { EntityManager } from 'typeorm'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; const tableName = 'calendarChannelEventAssociation'; export const seedCalendarChannelEventAssociations = async ( - entityManager: EntityManager, + entityManager: WorkspaceEntityManager, schemaName: string, ) => { await entityManager - .createQueryBuilder() + .createQueryBuilder(undefined, undefined, undefined, { + shouldBypassPermissionChecks: true, + }) .insert() .into(`${schemaName}.${tableName}`, [ 'id', diff --git a/packages/twenty-server/src/database/typeorm-seeds/workspace/calendar-channel.ts b/packages/twenty-server/src/database/typeorm-seeds/workspace/calendar-channel.ts index 14a4117ee..88383dd71 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/workspace/calendar-channel.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/workspace/calendar-channel.ts @@ -1,16 +1,17 @@ -import { EntityManager } from 'typeorm'; - import { DEV_SEED_CONNECTED_ACCOUNT_IDS } from 'src/database/typeorm-seeds/workspace/connected-account'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; import { CalendarChannelVisibility } from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity'; const tableName = 'calendarChannel'; export const seedCalendarChannels = async ( - entityManager: EntityManager, + entityManager: WorkspaceEntityManager, schemaName: string, ) => { await entityManager - .createQueryBuilder() + .createQueryBuilder(undefined, undefined, undefined, { + shouldBypassPermissionChecks: true, + }) .insert() .into(`${schemaName}.${tableName}`, [ 'id', diff --git a/packages/twenty-server/src/database/typeorm-seeds/workspace/calendar-event-participants.ts b/packages/twenty-server/src/database/typeorm-seeds/workspace/calendar-event-participants.ts index 724fd9b7b..1a59e4045 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/workspace/calendar-event-participants.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/workspace/calendar-event-participants.ts @@ -1,17 +1,18 @@ -import { EntityManager } from 'typeorm'; - import { DEV_SEED_PERSON_IDS } from 'src/database/typeorm-seeds/workspace/seedPeople'; import { DEV_SEED_WORKSPACE_MEMBER_IDS } from 'src/database/typeorm-seeds/workspace/workspace-members'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; import { CalendarEventParticipantResponseStatus } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity'; const tableName = 'calendarEventParticipant'; export const seedCalendarEventParticipants = async ( - entityManager: EntityManager, + entityManager: WorkspaceEntityManager, schemaName: string, ) => { await entityManager - .createQueryBuilder() + .createQueryBuilder(undefined, undefined, undefined, { + shouldBypassPermissionChecks: true, + }) .insert() .into(`${schemaName}.${tableName}`, [ 'id', diff --git a/packages/twenty-server/src/database/typeorm-seeds/workspace/calendar-events.ts b/packages/twenty-server/src/database/typeorm-seeds/workspace/calendar-events.ts index 6969213f7..fd4b0c729 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/workspace/calendar-events.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/workspace/calendar-events.ts @@ -1,13 +1,15 @@ -import { EntityManager } from 'typeorm'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; const tableName = 'calendarEvent'; export const seedCalendarEvents = async ( - entityManager: EntityManager, + entityManager: WorkspaceEntityManager, schemaName: string, ) => { await entityManager - .createQueryBuilder() + .createQueryBuilder(undefined, undefined, undefined, { + shouldBypassPermissionChecks: true, + }) .insert() .into(`${schemaName}.${tableName}`, [ 'id', diff --git a/packages/twenty-server/src/database/typeorm-seeds/workspace/companies.ts b/packages/twenty-server/src/database/typeorm-seeds/workspace/companies.ts index f067d067a..1fdc180d7 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/workspace/companies.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/workspace/companies.ts @@ -1,6 +1,5 @@ -import { EntityManager } from 'typeorm'; - import { DEV_SEED_WORKSPACE_MEMBER_IDS } from 'src/database/typeorm-seeds/workspace/workspace-members'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; const tableName = 'company'; @@ -21,11 +20,13 @@ export const DEV_SEED_COMPANY_IDS = { }; export const seedCompanies = async ( - entityManager: EntityManager, + entityManager: WorkspaceEntityManager, schemaName: string, ) => { await entityManager - .createQueryBuilder() + .createQueryBuilder(undefined, undefined, undefined, { + shouldBypassPermissionChecks: true, + }) .insert() .into(`${schemaName}.${tableName}`, [ 'id', diff --git a/packages/twenty-server/src/database/typeorm-seeds/workspace/connected-account.ts b/packages/twenty-server/src/database/typeorm-seeds/workspace/connected-account.ts index a35e5730a..a7d5573ca 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/workspace/connected-account.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/workspace/connected-account.ts @@ -1,6 +1,5 @@ -import { EntityManager } from 'typeorm'; - import { DEV_SEED_WORKSPACE_MEMBER_IDS } from 'src/database/typeorm-seeds/workspace/workspace-members'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; const tableName = 'connectedAccount'; @@ -11,11 +10,13 @@ export const DEV_SEED_CONNECTED_ACCOUNT_IDS = { }; export const seedConnectedAccount = async ( - entityManager: EntityManager, + entityManager: WorkspaceEntityManager, schemaName: string, ) => { await entityManager - .createQueryBuilder() + .createQueryBuilder(undefined, undefined, undefined, { + shouldBypassPermissionChecks: true, + }) .insert() .into(`${schemaName}.${tableName}`, [ 'id', diff --git a/packages/twenty-server/src/database/typeorm-seeds/workspace/favorites.ts b/packages/twenty-server/src/database/typeorm-seeds/workspace/favorites.ts index 53d9b50d8..78bb6433c 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/workspace/favorites.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/workspace/favorites.ts @@ -1,15 +1,18 @@ -import { EntityManager } from 'typeorm'; import { v4 } from 'uuid'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; + const tableName = 'favorite'; export const seedWorkspaceFavorites = async ( viewIds: string[], - entityManager: EntityManager, + entityManager: WorkspaceEntityManager, schemaName: string, ) => { await entityManager - .createQueryBuilder() + .createQueryBuilder(undefined, undefined, undefined, { + shouldBypassPermissionChecks: true, + }) .insert() .into(`${schemaName}.${tableName}`, ['id', 'viewId', 'position']) .values( diff --git a/packages/twenty-server/src/database/typeorm-seeds/workspace/message-channel-message-associations.ts b/packages/twenty-server/src/database/typeorm-seeds/workspace/message-channel-message-associations.ts index e4ab29ec6..633c6cd17 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/workspace/message-channel-message-associations.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/workspace/message-channel-message-associations.ts @@ -1,7 +1,6 @@ -import { EntityManager } from 'typeorm'; - import { DEV_SEED_MESSAGE_CHANNEL_IDS } from 'src/database/typeorm-seeds/workspace/message-channels'; import { DEV_SEED_MESSAGE_IDS } from 'src/database/typeorm-seeds/workspace/messages'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; import { MessageDirection } from 'src/modules/messaging/common/enums/message-direction.enum'; const tableName = 'messageChannelMessageAssociation'; @@ -13,11 +12,13 @@ export const DEV_SEED_MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_IDS = { }; export const seedMessageChannelMessageAssociation = async ( - entityManager: EntityManager, + entityManager: WorkspaceEntityManager, schemaName: string, ) => { await entityManager - .createQueryBuilder() + .createQueryBuilder(undefined, undefined, undefined, { + shouldBypassPermissionChecks: true, + }) .insert() .into(`${schemaName}.${tableName}`, [ 'id', diff --git a/packages/twenty-server/src/database/typeorm-seeds/workspace/message-channels.ts b/packages/twenty-server/src/database/typeorm-seeds/workspace/message-channels.ts index 79ddfcacb..60ea32a8c 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/workspace/message-channels.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/workspace/message-channels.ts @@ -1,6 +1,5 @@ -import { EntityManager } from 'typeorm'; - import { DEV_SEED_CONNECTED_ACCOUNT_IDS } from 'src/database/typeorm-seeds/workspace/connected-account'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; import { MessageChannelSyncStage, MessageChannelVisibility, @@ -15,11 +14,13 @@ export const DEV_SEED_MESSAGE_CHANNEL_IDS = { }; export const seedMessageChannel = async ( - entityManager: EntityManager, + entityManager: WorkspaceEntityManager, schemaName: string, ) => { await entityManager - .createQueryBuilder() + .createQueryBuilder(undefined, undefined, undefined, { + shouldBypassPermissionChecks: true, + }) .insert() .into(`${schemaName}.${tableName}`, [ 'id', diff --git a/packages/twenty-server/src/database/typeorm-seeds/workspace/message-participants.ts b/packages/twenty-server/src/database/typeorm-seeds/workspace/message-participants.ts index cc59dd53d..7865a109f 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/workspace/message-participants.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/workspace/message-participants.ts @@ -1,8 +1,7 @@ -import { EntityManager } from 'typeorm'; - import { DEV_SEED_MESSAGE_IDS } from 'src/database/typeorm-seeds/workspace/messages'; import { DEV_SEED_PERSON_IDS } from 'src/database/typeorm-seeds/workspace/seedPeople'; import { DEV_SEED_WORKSPACE_MEMBER_IDS } from 'src/database/typeorm-seeds/workspace/workspace-members'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; const tableName = 'messageParticipant'; @@ -16,11 +15,13 @@ export const DEV_SEED_MESSAGE_PARTICIPANT_IDS = { }; export const seedMessageParticipant = async ( - entityManager: EntityManager, + entityManager: WorkspaceEntityManager, schemaName: string, ) => { await entityManager - .createQueryBuilder() + .createQueryBuilder(undefined, undefined, undefined, { + shouldBypassPermissionChecks: true, + }) .insert() .into(`${schemaName}.${tableName}`, [ 'id', diff --git a/packages/twenty-server/src/database/typeorm-seeds/workspace/message-thread-subscribers.ts b/packages/twenty-server/src/database/typeorm-seeds/workspace/message-thread-subscribers.ts index 637446cd9..91b62ec00 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/workspace/message-thread-subscribers.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/workspace/message-thread-subscribers.ts @@ -1,4 +1,4 @@ -import { EntityManager } from 'typeorm'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; const tableName = 'messageThreadSubscriber'; @@ -26,11 +26,13 @@ export const DEV_SEED_USER_IDS = { }; export const seedMessageThreadSubscribers = async ( - entityManager: EntityManager, + entityManager: WorkspaceEntityManager, schemaName: string, ) => { await entityManager - .createQueryBuilder() + .createQueryBuilder(undefined, undefined, undefined, { + shouldBypassPermissionChecks: true, + }) .insert() .into(`${schemaName}.${tableName}`, [ 'id', diff --git a/packages/twenty-server/src/database/typeorm-seeds/workspace/message-threads.ts b/packages/twenty-server/src/database/typeorm-seeds/workspace/message-threads.ts index a7d8ea1df..a5ce1e62f 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/workspace/message-threads.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/workspace/message-threads.ts @@ -1,4 +1,4 @@ -import { EntityManager } from 'typeorm'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; const tableName = 'messageThread'; @@ -11,11 +11,13 @@ export const DEV_SEED_MESSAGE_THREAD_IDS = { }; export const seedMessageThread = async ( - entityManager: EntityManager, + entityManager: WorkspaceEntityManager, schemaName: string, ) => { await entityManager - .createQueryBuilder() + .createQueryBuilder(undefined, undefined, undefined, { + shouldBypassPermissionChecks: true, + }) .insert() .into(`${schemaName}.${tableName}`, [ 'id', diff --git a/packages/twenty-server/src/database/typeorm-seeds/workspace/messages.ts b/packages/twenty-server/src/database/typeorm-seeds/workspace/messages.ts index b8e0c1af8..1c6c041b1 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/workspace/messages.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/workspace/messages.ts @@ -1,6 +1,5 @@ -import { EntityManager } from 'typeorm'; - import { DEV_SEED_MESSAGE_THREAD_IDS } from 'src/database/typeorm-seeds/workspace/message-threads'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; const tableName = 'message'; @@ -11,11 +10,13 @@ export const DEV_SEED_MESSAGE_IDS = { }; export const seedMessage = async ( - entityManager: EntityManager, + entityManager: WorkspaceEntityManager, schemaName: string, ) => { await entityManager - .createQueryBuilder() + .createQueryBuilder(undefined, undefined, undefined, { + shouldBypassPermissionChecks: true, + }) .insert() .into(`${schemaName}.${tableName}`, [ 'id', diff --git a/packages/twenty-server/src/database/typeorm-seeds/workspace/opportunities.ts b/packages/twenty-server/src/database/typeorm-seeds/workspace/opportunities.ts index 2a160ddc1..b8ec3035f 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/workspace/opportunities.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/workspace/opportunities.ts @@ -1,8 +1,7 @@ -import { EntityManager } from 'typeorm'; - import { DEV_SEED_COMPANY_IDS } from 'src/database/typeorm-seeds/workspace/companies'; import { DEV_SEED_PERSON_IDS } from 'src/database/typeorm-seeds/workspace/seedPeople'; import { DEV_SEED_WORKSPACE_MEMBER_IDS } from 'src/database/typeorm-seeds/workspace/workspace-members'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; const tableName = 'opportunity'; @@ -14,11 +13,13 @@ export const DEV_SEED_OPPORTUNITY_IDS = { }; export const seedOpportunity = async ( - entityManager: EntityManager, + entityManager: WorkspaceEntityManager, schemaName: string, ) => { await entityManager - .createQueryBuilder() + .createQueryBuilder(undefined, undefined, undefined, { + shouldBypassPermissionChecks: true, + }) .insert() .into(`${schemaName}.${tableName}`, [ 'id', diff --git a/packages/twenty-server/src/database/typeorm-seeds/workspace/seedPeople.ts b/packages/twenty-server/src/database/typeorm-seeds/workspace/seedPeople.ts index 08b87607c..a06bd97f4 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/workspace/seedPeople.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/workspace/seedPeople.ts @@ -1,7 +1,6 @@ -import { EntityManager } from 'typeorm'; - import { DEV_SEED_COMPANY_IDS } from 'src/database/typeorm-seeds/workspace/companies'; import { DEV_SEED_WORKSPACE_MEMBER_IDS } from 'src/database/typeorm-seeds/workspace/workspace-members'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; const tableName = 'person'; @@ -24,11 +23,13 @@ export const DEV_SEED_PERSON_IDS = { }; export const seedPeople = async ( - entityManager: EntityManager, + entityManager: WorkspaceEntityManager, schemaName: string, ) => { await entityManager - .createQueryBuilder() + .createQueryBuilder(undefined, undefined, undefined, { + shouldBypassPermissionChecks: true, + }) .insert() .into(`${schemaName}.${tableName}`, [ 'id', diff --git a/packages/twenty-server/src/database/typeorm-seeds/workspace/workspace-members.ts b/packages/twenty-server/src/database/typeorm-seeds/workspace/workspace-members.ts index f0084dd3a..732db5b3e 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/workspace/workspace-members.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/workspace/workspace-members.ts @@ -1,11 +1,10 @@ -import { EntityManager } from 'typeorm'; - +import { DEV_SEED_USER_IDS } from 'src/database/typeorm-seeds/core/users'; import { - SEED_APPLE_WORKSPACE_ID, SEED_ACME_WORKSPACE_ID, + SEED_APPLE_WORKSPACE_ID, } from 'src/database/typeorm-seeds/core/workspaces'; import { WorkspaceMember } from 'src/engine/core-modules/user/dtos/workspace-member.dto'; -import { DEV_SEED_USER_IDS } from 'src/database/typeorm-seeds/core/users'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; const tableName = 'workspaceMember'; @@ -26,7 +25,7 @@ type WorkspaceMembers = Pick< }; export const seedWorkspaceMember = async ( - entityManager: EntityManager, + entityManager: WorkspaceEntityManager, schemaName: string, workspaceId: string, ) => { @@ -78,7 +77,9 @@ export const seedWorkspaceMember = async ( ]; } await entityManager - .createQueryBuilder() + .createQueryBuilder(undefined, undefined, undefined, { + shouldBypassPermissionChecks: true, + }) .insert() .into(`${schemaName}.${tableName}`, [ 'id', diff --git a/packages/twenty-server/src/engine/core-modules/auth/services/google-apis.service.ts b/packages/twenty-server/src/engine/core-modules/auth/services/google-apis.service.ts index 8baa9a08c..df25f71c3 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/services/google-apis.service.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/services/google-apis.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { ConnectedAccountProvider } from 'twenty-shared/types'; -import { EntityManager, Repository } from 'typeorm'; +import { Repository } from 'typeorm'; import { v4 } from 'uuid'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; @@ -12,6 +12,7 @@ import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queu import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service'; import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; import { WorkspaceEventEmitter } from 'src/engine/workspace-event-emitter/workspace-event-emitter'; import { @@ -103,202 +104,208 @@ export class GoogleAPIsService { const scopes = getGoogleApisOauthScopes(); - await workspaceDataSource.transaction(async (manager: EntityManager) => { - if (!existingAccountId) { - const newConnectedAccount = await connectedAccountRepository.save( - { - id: newOrExistingConnectedAccountId, - handle, - provider: ConnectedAccountProvider.GOOGLE, - accessToken: input.accessToken, - refreshToken: input.refreshToken, - accountOwnerId: workspaceMemberId, - scopes, - }, - {}, - manager, - ); - - const connectedAccountMetadata = - await this.objectMetadataRepository.findOneOrFail({ - where: { nameSingular: 'connectedAccount', workspaceId }, - }); - - this.workspaceEventEmitter.emitDatabaseBatchEvent({ - objectMetadataNameSingular: 'connectedAccount', - action: DatabaseEventAction.CREATED, - events: [ + await workspaceDataSource.transaction( + async (manager: WorkspaceEntityManager) => { + if (!existingAccountId) { + const newConnectedAccount = await connectedAccountRepository.save( { - recordId: newConnectedAccount.id, - objectMetadata: connectedAccountMetadata, - properties: { - after: newConnectedAccount, - }, - }, - ], - workspaceId, - }); - - const newMessageChannel = await messageChannelRepository.save( - { - id: v4(), - connectedAccountId: newOrExistingConnectedAccountId, - type: MessageChannelType.EMAIL, - handle, - visibility: - messageVisibility || MessageChannelVisibility.SHARE_EVERYTHING, - syncStatus: MessageChannelSyncStatus.ONGOING, - }, - {}, - manager, - ); - - const messageChannelMetadata = - await this.objectMetadataRepository.findOneOrFail({ - where: { nameSingular: 'messageChannel', workspaceId }, - }); - - this.workspaceEventEmitter.emitDatabaseBatchEvent({ - objectMetadataNameSingular: 'messageChannel', - action: DatabaseEventAction.CREATED, - events: [ - { - recordId: newMessageChannel.id, - objectMetadata: messageChannelMetadata, - properties: { - after: newMessageChannel, - }, - }, - ], - workspaceId, - }); - - if (isCalendarEnabled) { - const newCalendarChannel = await calendarChannelRepository.save( - { - id: v4(), - connectedAccountId: newOrExistingConnectedAccountId, + id: newOrExistingConnectedAccountId, handle, - visibility: - calendarVisibility || - CalendarChannelVisibility.SHARE_EVERYTHING, + provider: ConnectedAccountProvider.GOOGLE, + accessToken: input.accessToken, + refreshToken: input.refreshToken, + accountOwnerId: workspaceMemberId, + scopes, }, {}, manager, ); - const calendarChannelMetadata = + const connectedAccountMetadata = await this.objectMetadataRepository.findOneOrFail({ - where: { nameSingular: 'calendarChannel', workspaceId }, + where: { nameSingular: 'connectedAccount', workspaceId }, }); this.workspaceEventEmitter.emitDatabaseBatchEvent({ - objectMetadataNameSingular: 'calendarChannel', + objectMetadataNameSingular: 'connectedAccount', action: DatabaseEventAction.CREATED, events: [ { - recordId: newCalendarChannel.id, - objectMetadata: calendarChannelMetadata, + recordId: newConnectedAccount.id, + objectMetadata: connectedAccountMetadata, properties: { - after: newCalendarChannel, + after: newConnectedAccount, }, }, ], workspaceId, }); - } - } else { - const updatedConnectedAccount = await connectedAccountRepository.update( - { - id: newOrExistingConnectedAccountId, - }, - { - accessToken: input.accessToken, - refreshToken: input.refreshToken, - scopes, - }, - manager, - ); - const connectedAccountMetadata = - await this.objectMetadataRepository.findOneOrFail({ - where: { nameSingular: 'connectedAccount', workspaceId }, - }); - - this.workspaceEventEmitter.emitDatabaseBatchEvent({ - objectMetadataNameSingular: 'connectedAccount', - action: DatabaseEventAction.UPDATED, - events: [ + const newMessageChannel = await messageChannelRepository.save( { - recordId: newOrExistingConnectedAccountId, - objectMetadata: connectedAccountMetadata, - properties: { - before: connectedAccount, - after: { - ...connectedAccount, - ...updatedConnectedAccount.raw[0], - }, - }, + id: v4(), + connectedAccountId: newOrExistingConnectedAccountId, + type: MessageChannelType.EMAIL, + handle, + visibility: + messageVisibility || MessageChannelVisibility.SHARE_EVERYTHING, + syncStatus: MessageChannelSyncStatus.ONGOING, }, - ], - workspaceId, - }); - - const workspaceMemberRepository = - await this.twentyORMGlobalManager.getRepositoryForWorkspace( - workspaceId, - 'workspaceMember', + {}, + manager, ); - const workspaceMember = await workspaceMemberRepository.findOneOrFail({ - where: { id: workspaceMemberId }, - }); + const messageChannelMetadata = + await this.objectMetadataRepository.findOneOrFail({ + where: { nameSingular: 'messageChannel', workspaceId }, + }); - const userId = workspaceMember.userId; - - await this.accountsToReconnectService.removeAccountToReconnect( - userId, - workspaceId, - newOrExistingConnectedAccountId, - ); - - const messageChannels = await messageChannelRepository.find({ - where: { connectedAccountId: newOrExistingConnectedAccountId }, - }); - - const messageChannelUpdates = await messageChannelRepository.update( - { - connectedAccountId: newOrExistingConnectedAccountId, - }, - { - syncStage: MessageChannelSyncStage.FULL_MESSAGE_LIST_FETCH_PENDING, - syncStatus: null, - syncCursor: '', - syncStageStartedAt: null, - }, - manager, - ); - - const messageChannelMetadata = - await this.objectMetadataRepository.findOneOrFail({ - where: { nameSingular: 'messageChannel', workspaceId }, + this.workspaceEventEmitter.emitDatabaseBatchEvent({ + objectMetadataNameSingular: 'messageChannel', + action: DatabaseEventAction.CREATED, + events: [ + { + recordId: newMessageChannel.id, + objectMetadata: messageChannelMetadata, + properties: { + after: newMessageChannel, + }, + }, + ], + workspaceId, }); - this.workspaceEventEmitter.emitDatabaseBatchEvent({ - objectMetadataNameSingular: 'messageChannel', - action: DatabaseEventAction.UPDATED, - events: messageChannels.map((messageChannel) => ({ - recordId: messageChannel.id, - objectMetadata: messageChannelMetadata, - properties: { - before: messageChannel, - after: { ...messageChannel, ...messageChannelUpdates.raw[0] }, + if (isCalendarEnabled) { + const newCalendarChannel = await calendarChannelRepository.save( + { + id: v4(), + connectedAccountId: newOrExistingConnectedAccountId, + handle, + visibility: + calendarVisibility || + CalendarChannelVisibility.SHARE_EVERYTHING, + }, + {}, + manager, + ); + + const calendarChannelMetadata = + await this.objectMetadataRepository.findOneOrFail({ + where: { nameSingular: 'calendarChannel', workspaceId }, + }); + + this.workspaceEventEmitter.emitDatabaseBatchEvent({ + objectMetadataNameSingular: 'calendarChannel', + action: DatabaseEventAction.CREATED, + events: [ + { + recordId: newCalendarChannel.id, + objectMetadata: calendarChannelMetadata, + properties: { + after: newCalendarChannel, + }, + }, + ], + workspaceId, + }); + } + } else { + const updatedConnectedAccount = + await connectedAccountRepository.update( + { + id: newOrExistingConnectedAccountId, + }, + { + accessToken: input.accessToken, + refreshToken: input.refreshToken, + scopes, + }, + manager, + ); + + const connectedAccountMetadata = + await this.objectMetadataRepository.findOneOrFail({ + where: { nameSingular: 'connectedAccount', workspaceId }, + }); + + this.workspaceEventEmitter.emitDatabaseBatchEvent({ + objectMetadataNameSingular: 'connectedAccount', + action: DatabaseEventAction.UPDATED, + events: [ + { + recordId: newOrExistingConnectedAccountId, + objectMetadata: connectedAccountMetadata, + properties: { + before: connectedAccount, + after: { + ...connectedAccount, + ...updatedConnectedAccount.raw[0], + }, + }, + }, + ], + workspaceId, + }); + + const workspaceMemberRepository = + await this.twentyORMGlobalManager.getRepositoryForWorkspace( + workspaceId, + 'workspaceMember', + ); + + const workspaceMember = await workspaceMemberRepository.findOneOrFail( + { + where: { id: workspaceMemberId }, }, - })), - workspaceId, - }); - } - }); + ); + + const userId = workspaceMember.userId; + + await this.accountsToReconnectService.removeAccountToReconnect( + userId, + workspaceId, + newOrExistingConnectedAccountId, + ); + + const messageChannels = await messageChannelRepository.find({ + where: { connectedAccountId: newOrExistingConnectedAccountId }, + }); + + const messageChannelUpdates = await messageChannelRepository.update( + { + connectedAccountId: newOrExistingConnectedAccountId, + }, + { + syncStage: + MessageChannelSyncStage.FULL_MESSAGE_LIST_FETCH_PENDING, + syncStatus: null, + syncCursor: '', + syncStageStartedAt: null, + }, + manager, + ); + + const messageChannelMetadata = + await this.objectMetadataRepository.findOneOrFail({ + where: { nameSingular: 'messageChannel', workspaceId }, + }); + + this.workspaceEventEmitter.emitDatabaseBatchEvent({ + objectMetadataNameSingular: 'messageChannel', + action: DatabaseEventAction.UPDATED, + events: messageChannels.map((messageChannel) => ({ + recordId: messageChannel.id, + objectMetadata: messageChannelMetadata, + properties: { + before: messageChannel, + after: { ...messageChannel, ...messageChannelUpdates.raw[0] }, + }, + })), + workspaceId, + }); + } + }, + ); if (this.twentyConfigService.get('MESSAGING_PROVIDER_GMAIL_ENABLED')) { const messageChannels = await messageChannelRepository.find({ diff --git a/packages/twenty-server/src/engine/core-modules/auth/services/microsoft-apis.service.ts b/packages/twenty-server/src/engine/core-modules/auth/services/microsoft-apis.service.ts index de544b302..54a8c3404 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/services/microsoft-apis.service.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/services/microsoft-apis.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { ConnectedAccountProvider } from 'twenty-shared/types'; -import { EntityManager, Repository } from 'typeorm'; +import { Repository } from 'typeorm'; import { v4 } from 'uuid'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; @@ -12,6 +12,7 @@ import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queu import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service'; import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; import { WorkspaceEventEmitter } from 'src/engine/workspace-event-emitter/workspace-event-emitter'; import { @@ -107,226 +108,232 @@ export class MicrosoftAPIsService { const scopes = getMicrosoftApisOauthScopes(); - await workspaceDataSource.transaction(async (manager: EntityManager) => { - if (!existingAccountId) { - const newConnectedAccount = await connectedAccountRepository.save( - { - id: newOrExistingConnectedAccountId, - handle, - provider: ConnectedAccountProvider.MICROSOFT, - accessToken: input.accessToken, - refreshToken: input.refreshToken, - accountOwnerId: workspaceMemberId, - scopes, - }, - {}, - manager, - ); - - const connectedAccountMetadata = - await this.objectMetadataRepository.findOneOrFail({ - where: { nameSingular: 'connectedAccount', workspaceId }, - }); - - this.workspaceEventEmitter.emitDatabaseBatchEvent({ - objectMetadataNameSingular: 'connectedAccount', - action: DatabaseEventAction.CREATED, - events: [ + await workspaceDataSource.transaction( + async (manager: WorkspaceEntityManager) => { + if (!existingAccountId) { + const newConnectedAccount = await connectedAccountRepository.save( { - recordId: newConnectedAccount.id, - objectMetadata: connectedAccountMetadata, - properties: { - after: newConnectedAccount, - }, - }, - ], - workspaceId, - }); - - const newMessageChannel = await messageChannelRepository.save( - { - id: v4(), - connectedAccountId: newOrExistingConnectedAccountId, - type: MessageChannelType.EMAIL, - handle, - visibility: - messageVisibility || MessageChannelVisibility.SHARE_EVERYTHING, - syncStatus: MessageChannelSyncStatus.ONGOING, - }, - {}, - manager, - ); - - await messageFolderRepository.save( - { - id: v4(), - messageChannelId: newMessageChannel.id, - name: MessageFolderName.INBOX, - syncCursor: '', - }, - {}, - manager, - ); - - await messageFolderRepository.save( - { - id: v4(), - messageChannelId: newMessageChannel.id, - name: MessageFolderName.SENT_ITEMS, - syncCursor: '', - }, - {}, - manager, - ); - - const messageChannelMetadata = - await this.objectMetadataRepository.findOneOrFail({ - where: { nameSingular: 'messageChannel', workspaceId }, - }); - - this.workspaceEventEmitter.emitDatabaseBatchEvent({ - objectMetadataNameSingular: 'messageChannel', - action: DatabaseEventAction.CREATED, - events: [ - { - recordId: newMessageChannel.id, - objectMetadata: messageChannelMetadata, - properties: { - after: newMessageChannel, - }, - }, - ], - workspaceId, - }); - - if ( - this.twentyConfigService.get('CALENDAR_PROVIDER_MICROSOFT_ENABLED') - ) { - const newCalendarChannel = await calendarChannelRepository.save( - { - id: v4(), - connectedAccountId: newOrExistingConnectedAccountId, + id: newOrExistingConnectedAccountId, handle, - visibility: - calendarVisibility || - CalendarChannelVisibility.SHARE_EVERYTHING, + provider: ConnectedAccountProvider.MICROSOFT, + accessToken: input.accessToken, + refreshToken: input.refreshToken, + accountOwnerId: workspaceMemberId, + scopes, }, {}, manager, ); - const calendarChannelMetadata = + const connectedAccountMetadata = await this.objectMetadataRepository.findOneOrFail({ - where: { nameSingular: 'calendarChannel', workspaceId }, + where: { nameSingular: 'connectedAccount', workspaceId }, }); this.workspaceEventEmitter.emitDatabaseBatchEvent({ - objectMetadataNameSingular: 'calendarChannel', + objectMetadataNameSingular: 'connectedAccount', action: DatabaseEventAction.CREATED, events: [ { - recordId: newCalendarChannel.id, - objectMetadata: calendarChannelMetadata, + recordId: newConnectedAccount.id, + objectMetadata: connectedAccountMetadata, properties: { - after: newCalendarChannel, + after: newConnectedAccount, }, }, ], workspaceId, }); - } - } else { - const updatedConnectedAccount = await connectedAccountRepository.update( - { - id: newOrExistingConnectedAccountId, - }, - { - accessToken: input.accessToken, - refreshToken: input.refreshToken, - scopes, - }, - manager, - ); - const connectedAccountMetadata = - await this.objectMetadataRepository.findOneOrFail({ - where: { nameSingular: 'connectedAccount', workspaceId }, - }); - - this.workspaceEventEmitter.emitDatabaseBatchEvent({ - objectMetadataNameSingular: 'connectedAccount', - action: DatabaseEventAction.UPDATED, - events: [ + const newMessageChannel = await messageChannelRepository.save( { - recordId: newOrExistingConnectedAccountId, - objectMetadata: connectedAccountMetadata, - properties: { - before: connectedAccount, - after: { - ...connectedAccount, - ...updatedConnectedAccount.raw[0], - }, - }, + id: v4(), + connectedAccountId: newOrExistingConnectedAccountId, + type: MessageChannelType.EMAIL, + handle, + visibility: + messageVisibility || MessageChannelVisibility.SHARE_EVERYTHING, + syncStatus: MessageChannelSyncStatus.ONGOING, }, - ], - workspaceId, - }); - - const workspaceMemberRepository = - await this.twentyORMGlobalManager.getRepositoryForWorkspace( - workspaceId, - 'workspaceMember', + {}, + manager, ); - const workspaceMember = await workspaceMemberRepository.findOneOrFail({ - where: { id: workspaceMemberId }, - }); + await messageFolderRepository.save( + { + id: v4(), + messageChannelId: newMessageChannel.id, + name: MessageFolderName.INBOX, + syncCursor: '', + }, + {}, + manager, + ); - const userId = workspaceMember.userId; + await messageFolderRepository.save( + { + id: v4(), + messageChannelId: newMessageChannel.id, + name: MessageFolderName.SENT_ITEMS, + syncCursor: '', + }, + {}, + manager, + ); - await this.accountsToReconnectService.removeAccountToReconnect( - userId, - workspaceId, - newOrExistingConnectedAccountId, - ); + const messageChannelMetadata = + await this.objectMetadataRepository.findOneOrFail({ + where: { nameSingular: 'messageChannel', workspaceId }, + }); - const messageChannels = await messageChannelRepository.find({ - where: { connectedAccountId: newOrExistingConnectedAccountId }, - }); - - const messageChannelUpdates = await messageChannelRepository.update( - { - connectedAccountId: newOrExistingConnectedAccountId, - }, - { - syncStage: MessageChannelSyncStage.FULL_MESSAGE_LIST_FETCH_PENDING, - syncStatus: MessageChannelSyncStatus.ONGOING, - syncCursor: '', - syncStageStartedAt: null, - }, - manager, - ); - - const messageChannelMetadata = - await this.objectMetadataRepository.findOneOrFail({ - where: { nameSingular: 'messageChannel', workspaceId }, + this.workspaceEventEmitter.emitDatabaseBatchEvent({ + objectMetadataNameSingular: 'messageChannel', + action: DatabaseEventAction.CREATED, + events: [ + { + recordId: newMessageChannel.id, + objectMetadata: messageChannelMetadata, + properties: { + after: newMessageChannel, + }, + }, + ], + workspaceId, }); - this.workspaceEventEmitter.emitDatabaseBatchEvent({ - objectMetadataNameSingular: 'messageChannel', - action: DatabaseEventAction.UPDATED, - events: messageChannels.map((messageChannel) => ({ - recordId: messageChannel.id, - objectMetadata: messageChannelMetadata, - properties: { - before: messageChannel, - after: { ...messageChannel, ...messageChannelUpdates.raw[0] }, + if ( + this.twentyConfigService.get('CALENDAR_PROVIDER_MICROSOFT_ENABLED') + ) { + const newCalendarChannel = await calendarChannelRepository.save( + { + id: v4(), + connectedAccountId: newOrExistingConnectedAccountId, + handle, + visibility: + calendarVisibility || + CalendarChannelVisibility.SHARE_EVERYTHING, + }, + {}, + manager, + ); + + const calendarChannelMetadata = + await this.objectMetadataRepository.findOneOrFail({ + where: { nameSingular: 'calendarChannel', workspaceId }, + }); + + this.workspaceEventEmitter.emitDatabaseBatchEvent({ + objectMetadataNameSingular: 'calendarChannel', + action: DatabaseEventAction.CREATED, + events: [ + { + recordId: newCalendarChannel.id, + objectMetadata: calendarChannelMetadata, + properties: { + after: newCalendarChannel, + }, + }, + ], + workspaceId, + }); + } + } else { + const updatedConnectedAccount = + await connectedAccountRepository.update( + { + id: newOrExistingConnectedAccountId, + }, + { + accessToken: input.accessToken, + refreshToken: input.refreshToken, + scopes, + }, + manager, + ); + + const connectedAccountMetadata = + await this.objectMetadataRepository.findOneOrFail({ + where: { nameSingular: 'connectedAccount', workspaceId }, + }); + + this.workspaceEventEmitter.emitDatabaseBatchEvent({ + objectMetadataNameSingular: 'connectedAccount', + action: DatabaseEventAction.UPDATED, + events: [ + { + recordId: newOrExistingConnectedAccountId, + objectMetadata: connectedAccountMetadata, + properties: { + before: connectedAccount, + after: { + ...connectedAccount, + ...updatedConnectedAccount.raw[0], + }, + }, + }, + ], + workspaceId, + }); + + const workspaceMemberRepository = + await this.twentyORMGlobalManager.getRepositoryForWorkspace( + workspaceId, + 'workspaceMember', + ); + + const workspaceMember = await workspaceMemberRepository.findOneOrFail( + { + where: { id: workspaceMemberId }, }, - })), - workspaceId, - }); - } - }); + ); + + const userId = workspaceMember.userId; + + await this.accountsToReconnectService.removeAccountToReconnect( + userId, + workspaceId, + newOrExistingConnectedAccountId, + ); + + const messageChannels = await messageChannelRepository.find({ + where: { connectedAccountId: newOrExistingConnectedAccountId }, + }); + + const messageChannelUpdates = await messageChannelRepository.update( + { + connectedAccountId: newOrExistingConnectedAccountId, + }, + { + syncStage: + MessageChannelSyncStage.FULL_MESSAGE_LIST_FETCH_PENDING, + syncStatus: MessageChannelSyncStatus.ONGOING, + syncCursor: '', + syncStageStartedAt: null, + }, + manager, + ); + + const messageChannelMetadata = + await this.objectMetadataRepository.findOneOrFail({ + where: { nameSingular: 'messageChannel', workspaceId }, + }); + + this.workspaceEventEmitter.emitDatabaseBatchEvent({ + objectMetadataNameSingular: 'messageChannel', + action: DatabaseEventAction.UPDATED, + events: messageChannels.map((messageChannel) => ({ + recordId: messageChannel.id, + objectMetadata: messageChannelMetadata, + properties: { + before: messageChannel, + after: { ...messageChannel, ...messageChannelUpdates.raw[0] }, + }, + })), + workspaceId, + }); + } + }, + ); if (this.twentyConfigService.get('MESSAGING_PROVIDER_MICROSOFT_ENABLED')) { const messageChannels = await messageChannelRepository.find({ diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/services/field-metadata-related-records.service.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/services/field-metadata-related-records.service.ts index cbe1822e3..b0dcaa658 100644 --- a/packages/twenty-server/src/engine/metadata-modules/field-metadata/services/field-metadata-related-records.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/services/field-metadata-related-records.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@nestjs/common'; -import { EntityManager, In } from 'typeorm'; +import { In } from 'typeorm'; import { FieldMetadataComplexOption, @@ -28,7 +28,6 @@ export class FieldMetadataRelatedRecordsService { public async updateRelatedViewGroups( oldFieldMetadata: FieldMetadataEntity, newFieldMetadata: FieldMetadataEntity, - transactionManager?: EntityManager, ): Promise { if ( !isSelectFieldMetadataType(newFieldMetadata.type) || @@ -67,7 +66,7 @@ export class FieldMetadataRelatedRecordsService { }), ); - await viewGroupRepository.insert(viewGroupsToCreate, transactionManager); + await viewGroupRepository.insert(viewGroupsToCreate); for (const { old: oldOption, new: newOption } of updated) { const existingViewGroup = view.viewGroups.find( @@ -83,25 +82,20 @@ export class FieldMetadataRelatedRecordsService { await viewGroupRepository.update( { id: existingViewGroup.id }, { fieldValue: newOption.value }, - transactionManager, ); } const valuesToDelete = deleted.map((option) => option.value); - await viewGroupRepository.delete( - { - fieldMetadataId: newFieldMetadata.id, - fieldValue: In(valuesToDelete), - }, - transactionManager, - ); + await viewGroupRepository.delete({ + fieldMetadataId: newFieldMetadata.id, + fieldValue: In(valuesToDelete), + }); await this.syncNoValueViewGroup( newFieldMetadata, view, viewGroupRepository, - transactionManager, ); } } @@ -110,7 +104,6 @@ export class FieldMetadataRelatedRecordsService { fieldMetadata: FieldMetadataEntity, view: ViewWorkspaceEntity, viewGroupRepository: WorkspaceRepository, - transactionManager?: EntityManager, ): Promise { const noValueGroup = view.viewGroups.find( (group) => group.fieldValue === '', @@ -126,12 +119,9 @@ export class FieldMetadataRelatedRecordsService { viewId: view.id, }); - await viewGroupRepository.insert(newGroup, transactionManager); + await viewGroupRepository.insert(newGroup); } else if (!fieldMetadata.isNullable && noValueGroup) { - await viewGroupRepository.delete( - { id: noValueGroup.id }, - transactionManager, - ); + await viewGroupRepository.delete({ id: noValueGroup.id }); } } diff --git a/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-server.service.ts b/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-server.service.ts index 1742f1d0b..63642ee23 100644 --- a/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-server.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-server.service.ts @@ -26,6 +26,7 @@ import { validateStringAgainstInjections, } from 'src/engine/metadata-modules/remote-server/utils/validate-remote-server-input.utils'; import { validateRemoteServerType } from 'src/engine/metadata-modules/remote-server/utils/validate-remote-server-type.util'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; @Injectable() @@ -79,7 +80,7 @@ export class RemoteServerService { } return this.metadataDataSource.transaction( - async (entityManager: EntityManager) => { + async (entityManager: WorkspaceEntityManager) => { const createdRemoteServer = entityManager.create( RemoteServerEntity, remoteServerToCreate, diff --git a/packages/twenty-server/src/engine/seeder/seeder.service.ts b/packages/twenty-server/src/engine/seeder/seeder.service.ts index 0bef15d51..1589f7d93 100644 --- a/packages/twenty-server/src/engine/seeder/seeder.service.ts +++ b/packages/twenty-server/src/engine/seeder/seeder.service.ts @@ -1,7 +1,8 @@ import { Injectable } from '@nestjs/common'; -import { capitalize, isDefined } from 'twenty-shared/utils'; import { FieldMetadataType } from 'twenty-shared/types'; +import { capitalize, isDefined } from 'twenty-shared/utils'; +import { DataSource, EntityManager } from 'typeorm'; import { ObjectMetadataSeed } from 'src/engine/seeder/interfaces/object-metadata-seed'; @@ -60,12 +61,13 @@ export class SeederService { const schemaName = this.workspaceDataSourceService.getSchemaName(workspaceId); - const workspaceDataSource = + const workspaceDataSource: DataSource = await this.workspaceDataSourceService.connectToWorkspaceDataSource( workspaceId, ); - const entityManager = workspaceDataSource.createEntityManager(); + const entityManager: EntityManager = + workspaceDataSource.createEntityManager(); const filteredFieldMetadataSeeds = objectMetadataSeed.fields.filter( (field) => diff --git a/packages/twenty-server/src/engine/twenty-orm/datasource/workspace.datasource.ts b/packages/twenty-server/src/engine/twenty-orm/datasource/workspace.datasource.ts index 3d4907121..c2aeb968a 100644 --- a/packages/twenty-server/src/engine/twenty-orm/datasource/workspace.datasource.ts +++ b/packages/twenty-server/src/engine/twenty-orm/datasource/workspace.datasource.ts @@ -5,12 +5,14 @@ import { EntityTarget, ObjectLiteral, QueryRunner, + ReplicationMode, } from 'typeorm'; import { FeatureFlagMap } from 'src/engine/core-modules/feature-flag/interfaces/feature-flag-map.interface'; import { WorkspaceInternalContext } from 'src/engine/twenty-orm/interfaces/workspace-internal-context.interface'; -import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/entity.manager'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; +import { WorkspaceQueryRunner } from 'src/engine/twenty-orm/query-runner/workspace-query-runner'; import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; export class WorkspaceDataSource extends DataSource { @@ -31,10 +33,10 @@ export class WorkspaceDataSource extends DataSource { ) { super(options); this.internalContext = internalContext; - // Recreate manager after internalContext has been initialized - this.manager = this.createEntityManager(); this.featureFlagMap = featureFlagMap; this.featureFlagMapVersion = featureFlagMapVersion; + // Recreate manager after internalContext has been initialized + this.manager = this.createEntityManager(); this.rolesPermissionsVersion = rolesPermissionsVersion; this.permissionsPerRoleId = permissionsPerRoleId; } @@ -65,6 +67,17 @@ export class WorkspaceDataSource extends DataSource { return new WorkspaceEntityManager(this.internalContext, this, queryRunner); } + override createQueryRunner( + mode = 'master' as ReplicationMode, + ): WorkspaceQueryRunner { + const queryRunner = this.driver.createQueryRunner(mode); + const manager = this.createEntityManager(queryRunner); + + Object.assign(queryRunner, { manager: manager }); + + return queryRunner as any as WorkspaceQueryRunner; + } + setRolesPermissionsVersion(rolesPermissionsVersion: string) { this.rolesPermissionsVersion = rolesPermissionsVersion; } diff --git a/packages/twenty-server/src/engine/twenty-orm/entity-manager/entity.manager.ts b/packages/twenty-server/src/engine/twenty-orm/entity-manager/entity.manager.ts deleted file mode 100644 index 6584b53d6..000000000 --- a/packages/twenty-server/src/engine/twenty-orm/entity-manager/entity.manager.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { - DataSource, - EntityManager, - EntityTarget, - ObjectLiteral, - QueryRunner, - Repository, -} from 'typeorm'; - -import { WorkspaceInternalContext } from 'src/engine/twenty-orm/interfaces/workspace-internal-context.interface'; - -import { WorkspaceDataSource } from 'src/engine/twenty-orm/datasource/workspace.datasource'; -import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; - -export class WorkspaceEntityManager extends EntityManager { - private readonly internalContext: WorkspaceInternalContext; - readonly repositories: Map>; - - constructor( - internalContext: WorkspaceInternalContext, - connection: DataSource, - queryRunner?: QueryRunner, - ) { - super(connection, queryRunner); - this.internalContext = internalContext; - this.repositories = new Map(); - } - - override getRepository( - target: EntityTarget, - shouldBypassPermissionChecks = false, - roleId?: string, - ): WorkspaceRepository { - const dataSource = this.connection as WorkspaceDataSource; - - const repositoryKey = this.getRepositoryKey({ - target, - dataSource, - roleId, - shouldBypassPermissionChecks, - }); - const repoFromMap = this.repositories.get(repositoryKey); - - if (repoFromMap) { - return repoFromMap as WorkspaceRepository; - } - - let objectPermissions = {}; - - if (roleId) { - const objectPermissionsByRoleId = dataSource.permissionsPerRoleId; - - objectPermissions = objectPermissionsByRoleId?.[roleId] ?? {}; - } - - const newRepository = new WorkspaceRepository( - this.internalContext, - target, - this, - dataSource.featureFlagMap, - this.queryRunner, - objectPermissions, - shouldBypassPermissionChecks, - ); - - this.repositories.set(repositoryKey, newRepository); - - return newRepository; - } - - private getRepositoryKey({ - target, - dataSource, - roleId, - shouldBypassPermissionChecks, - }: { - target: EntityTarget; - dataSource: WorkspaceDataSource; - shouldBypassPermissionChecks: boolean; - roleId?: string; - }) { - const repositoryPrefix = dataSource.getMetadata(target).name; - const roleIdSuffix = roleId ? `_${roleId}` : ''; - const rolesPermissionsVersionSuffix = dataSource.rolesPermissionsVersion - ? `_${dataSource.rolesPermissionsVersion}` - : ''; - const featureFlagMapVersionSuffix = dataSource.featureFlagMapVersion - ? `_${dataSource.featureFlagMapVersion}` - : ''; - - return shouldBypassPermissionChecks - ? `${repositoryPrefix}_bypass${featureFlagMapVersionSuffix}` - : `${repositoryPrefix}${roleIdSuffix}${rolesPermissionsVersionSuffix}${featureFlagMapVersionSuffix}`; - } -} diff --git a/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.ts b/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.ts new file mode 100644 index 000000000..9d8279eea --- /dev/null +++ b/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.ts @@ -0,0 +1,228 @@ +import { ObjectRecordsPermissions } from 'twenty-shared/types'; +import { + EntityManager, + EntityTarget, + InsertResult, + ObjectLiteral, + QueryRunner, + Repository, + SelectQueryBuilder, +} from 'typeorm'; +import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity'; +import { UpsertOptions } from 'typeorm/repository/UpsertOptions'; + +import { FeatureFlagMap } from 'src/engine/core-modules/feature-flag/interfaces/feature-flag-map.interface'; +import { WorkspaceInternalContext } from 'src/engine/twenty-orm/interfaces/workspace-internal-context.interface'; + +import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; +import { WorkspaceDataSource } from 'src/engine/twenty-orm/datasource/workspace.datasource'; +import { + OperationType, + validateOperationIsPermittedOrThrow, +} from 'src/engine/twenty-orm/repository/permissions.utils'; +import { WorkspaceSelectQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-select-query-builder'; +import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; + +export class WorkspaceEntityManager extends EntityManager { + private readonly internalContext: WorkspaceInternalContext; + readonly repositories: Map>; + declare connection: WorkspaceDataSource; + + constructor( + internalContext: WorkspaceInternalContext, + connection: WorkspaceDataSource, + queryRunner?: QueryRunner, + ) { + super(connection, queryRunner); + this.internalContext = internalContext; + this.repositories = new Map(); + } + + getFeatureFlagMap(): FeatureFlagMap { + return this.connection.featureFlagMap; + } + + override getRepository( + target: EntityTarget, + shouldBypassPermissionChecks = false, + roleId?: string, + ): WorkspaceRepository { + const dataSource = this.connection; + + const repositoryKey = this.getRepositoryKey({ + target, + dataSource, + roleId, + shouldBypassPermissionChecks, + }); + const repoFromMap = this.repositories.get(repositoryKey); + + if (repoFromMap) { + return repoFromMap as WorkspaceRepository; + } + + let objectPermissions = {}; + + if (roleId) { + const objectPermissionsByRoleId = dataSource.permissionsPerRoleId; + + objectPermissions = objectPermissionsByRoleId?.[roleId] ?? {}; + } + + const newRepository = new WorkspaceRepository( + this.internalContext, + target, + this, + dataSource.featureFlagMap, + this.queryRunner, + objectPermissions, + shouldBypassPermissionChecks, + ); + + this.repositories.set(repositoryKey, newRepository); + + return newRepository; + } + + override createQueryBuilder( + entityClassOrQueryRunner?: EntityTarget | QueryRunner, + alias?: string, + queryRunner?: QueryRunner, + options: { + shouldBypassPermissionChecks: boolean; + roleId?: string; + } = { + shouldBypassPermissionChecks: false, + }, + ): SelectQueryBuilder | WorkspaceSelectQueryBuilder { + let queryBuilder: SelectQueryBuilder; + + if (alias) { + queryBuilder = super.createQueryBuilder( + entityClassOrQueryRunner as EntityTarget, + alias as string, + queryRunner as QueryRunner | undefined, + ); + } else { + queryBuilder = super.createQueryBuilder( + entityClassOrQueryRunner as QueryRunner, + ); + } + + const featureFlagMap = this.getFeatureFlagMap(); + + const isPermissionsV2Enabled = + featureFlagMap[FeatureFlagKey.IsPermissionsV2Enabled]; + + if (!isPermissionsV2Enabled) { + return queryBuilder; + } else { + let objectPermissions = {}; + + if (options?.roleId) { + const dataSource = this.connection as WorkspaceDataSource; + const objectPermissionsByRoleId = dataSource.permissionsPerRoleId; + + objectPermissions = objectPermissionsByRoleId?.[options.roleId] ?? {}; + } + + return new WorkspaceSelectQueryBuilder( + queryBuilder, + objectPermissions, + this.internalContext, + options?.shouldBypassPermissionChecks ?? false, + ); + } + } + + override insert( + target: EntityTarget, + entityOrEntities: + | QueryDeepPartialEntity + | QueryDeepPartialEntity[], + options?: { + shouldBypassPermissionChecks?: boolean; + objectRecordsPermissions?: ObjectRecordsPermissions; + }, + ): Promise { + this.validatePermissions(target, 'insert', options); + + return super.insert(target, entityOrEntities); + } + + override upsert( + target: EntityTarget, + entityOrEntities: + | QueryDeepPartialEntity + | QueryDeepPartialEntity[], + conflictPathsOrOptions: string[] | UpsertOptions, + options?: { + shouldBypassPermissionChecks?: boolean; + objectRecordsPermissions?: ObjectRecordsPermissions; + }, + ): Promise { + this.validatePermissions(target, 'update', options); + + return super.upsert(target, entityOrEntities, conflictPathsOrOptions); + } + + private getRepositoryKey({ + target, + dataSource, + roleId, + shouldBypassPermissionChecks, + }: { + target: EntityTarget; + dataSource: WorkspaceDataSource; + shouldBypassPermissionChecks: boolean; + roleId?: string; + }) { + const repositoryPrefix = dataSource.getMetadata(target).name; + const roleIdSuffix = roleId ? `_${roleId}` : ''; + const rolesPermissionsVersionSuffix = dataSource.rolesPermissionsVersion + ? `_${dataSource.rolesPermissionsVersion}` + : ''; + const featureFlagMapVersionSuffix = dataSource.featureFlagMapVersion + ? `_${dataSource.featureFlagMapVersion}` + : ''; + + return shouldBypassPermissionChecks + ? `${repositoryPrefix}_bypass${featureFlagMapVersionSuffix}` + : `${repositoryPrefix}${roleIdSuffix}${rolesPermissionsVersionSuffix}${featureFlagMapVersionSuffix}`; + } + + private validatePermissions( + target: EntityTarget, + operationType: OperationType, + options?: { + shouldBypassPermissionChecks?: boolean; + objectRecordsPermissions?: ObjectRecordsPermissions; + }, + ): void { + const featureFlagMap = this.getFeatureFlagMap(); + + const isPermissionsV2Enabled = + featureFlagMap[FeatureFlagKey.IsPermissionsV2Enabled]; + + if (!isPermissionsV2Enabled) { + return; + } + + if (options?.shouldBypassPermissionChecks === true) { + return; + } + + validateOperationIsPermittedOrThrow({ + entityName: this.extractTargetNameSingularFromEntityTarget(target), + operationType, + objectRecordsPermissions: options?.objectRecordsPermissions ?? {}, + objectMetadataMaps: this.internalContext.objectMetadataMaps, + }); + } + + private extractTargetNameSingularFromEntityTarget( + target: EntityTarget, + ): string { + return this.connection.getMetadata(target).name; + } +} diff --git a/packages/twenty-server/src/engine/twenty-orm/query-runner/workspace-query-runner.ts b/packages/twenty-server/src/engine/twenty-orm/query-runner/workspace-query-runner.ts new file mode 100644 index 000000000..ac51d94e5 --- /dev/null +++ b/packages/twenty-server/src/engine/twenty-orm/query-runner/workspace-query-runner.ts @@ -0,0 +1,9 @@ +import { QueryRunner } from 'typeorm'; + +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; + +interface WorkspaceQueryRunner extends Omit { + manager: WorkspaceEntityManager; +} + +export { WorkspaceQueryRunner }; diff --git a/packages/twenty-server/src/engine/twenty-orm/repository/permissions.util.ts b/packages/twenty-server/src/engine/twenty-orm/repository/permissions.utils.ts similarity index 77% rename from packages/twenty-server/src/engine/twenty-orm/repository/permissions.util.ts rename to packages/twenty-server/src/engine/twenty-orm/repository/permissions.utils.ts index b2969bfb9..b2ec3a64c 100644 --- a/packages/twenty-server/src/engine/twenty-orm/repository/permissions.util.ts +++ b/packages/twenty-server/src/engine/twenty-orm/repository/permissions.utils.ts @@ -18,21 +18,27 @@ const getTargetEntityAndOperationType = (expressionMap: QueryExpressionMap) => { }; }; -export const validateQueryIsPermittedOrThrow = ( - expressionMap: QueryExpressionMap, - objectRecordsPermissions: ObjectRecordsPermissions, - objectMetadataMaps: ObjectMetadataMaps, - shouldBypassPermissionChecks: boolean, -) => { - if (shouldBypassPermissionChecks) { - return; - } - - const { mainEntity, operationType } = - getTargetEntityAndOperationType(expressionMap); +export type OperationType = + | 'select' + | 'insert' + | 'update' + | 'delete' + | 'restore' + | 'soft-delete'; +export const validateOperationIsPermittedOrThrow = ({ + entityName, + operationType, + objectRecordsPermissions, + objectMetadataMaps, +}: { + entityName: string; + operationType: OperationType; + objectRecordsPermissions: ObjectRecordsPermissions; + objectMetadataMaps: ObjectMetadataMaps; +}) => { const objectMetadataIdForEntity = - objectMetadataMaps.idByNameSingular[mainEntity]; + objectMetadataMaps.idByNameSingular[entityName]; const objectMetadataIsSystem = objectMetadataMaps.byId[objectMetadataIdForEntity]?.isSystem === true; @@ -41,7 +47,7 @@ export const validateQueryIsPermittedOrThrow = ( return; } - const permissionsForEntity = objectRecordsPermissions[mainEntity]; + const permissionsForEntity = objectRecordsPermissions[entityName]; switch (operationType) { case 'select': @@ -85,3 +91,24 @@ export const validateQueryIsPermittedOrThrow = ( ); } }; + +export const validateQueryIsPermittedOrThrow = ( + expressionMap: QueryExpressionMap, + objectRecordsPermissions: ObjectRecordsPermissions, + objectMetadataMaps: ObjectMetadataMaps, + shouldBypassPermissionChecks: boolean, +) => { + if (shouldBypassPermissionChecks) { + return; + } + + const { mainEntity, operationType } = + getTargetEntityAndOperationType(expressionMap); + + validateOperationIsPermittedOrThrow({ + entityName: mainEntity, + operationType: operationType as OperationType, + objectRecordsPermissions, + objectMetadataMaps, + }); +}; diff --git a/packages/twenty-server/src/engine/twenty-orm/repository/workspace-delete-query-builder.ts b/packages/twenty-server/src/engine/twenty-orm/repository/workspace-delete-query-builder.ts index a0c83f193..46dd60c2b 100644 --- a/packages/twenty-server/src/engine/twenty-orm/repository/workspace-delete-query-builder.ts +++ b/packages/twenty-server/src/engine/twenty-orm/repository/workspace-delete-query-builder.ts @@ -9,7 +9,7 @@ import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity import { WorkspaceInternalContext } from 'src/engine/twenty-orm/interfaces/workspace-internal-context.interface'; -import { validateQueryIsPermittedOrThrow } from 'src/engine/twenty-orm/repository/permissions.util'; +import { validateQueryIsPermittedOrThrow } from 'src/engine/twenty-orm/repository/permissions.utils'; import { WorkspaceSelectQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-select-query-builder'; import { WorkspaceSoftDeleteQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-soft-delete-query-builder'; import { WorkspaceUpdateQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-update-query-builder'; diff --git a/packages/twenty-server/src/engine/twenty-orm/repository/workspace-insert-query-builder.ts b/packages/twenty-server/src/engine/twenty-orm/repository/workspace-insert-query-builder.ts index edaafbaf3..d37f263e6 100644 --- a/packages/twenty-server/src/engine/twenty-orm/repository/workspace-insert-query-builder.ts +++ b/packages/twenty-server/src/engine/twenty-orm/repository/workspace-insert-query-builder.ts @@ -3,7 +3,7 @@ import { InsertQueryBuilder, ObjectLiteral } from 'typeorm'; import { WorkspaceInternalContext } from 'src/engine/twenty-orm/interfaces/workspace-internal-context.interface'; -import { validateQueryIsPermittedOrThrow } from 'src/engine/twenty-orm/repository/permissions.util'; +import { validateQueryIsPermittedOrThrow } from 'src/engine/twenty-orm/repository/permissions.utils'; import { WorkspaceDeleteQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-delete-query-builder'; import { WorkspaceSelectQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-select-query-builder'; import { WorkspaceSoftDeleteQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-soft-delete-query-builder'; diff --git a/packages/twenty-server/src/engine/twenty-orm/repository/workspace-select-query-builder.ts b/packages/twenty-server/src/engine/twenty-orm/repository/workspace-select-query-builder.ts index 69362a96a..a75eb6eef 100644 --- a/packages/twenty-server/src/engine/twenty-orm/repository/workspace-select-query-builder.ts +++ b/packages/twenty-server/src/engine/twenty-orm/repository/workspace-select-query-builder.ts @@ -4,7 +4,7 @@ import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity import { WorkspaceInternalContext } from 'src/engine/twenty-orm/interfaces/workspace-internal-context.interface'; -import { validateQueryIsPermittedOrThrow } from 'src/engine/twenty-orm/repository/permissions.util'; +import { validateQueryIsPermittedOrThrow } from 'src/engine/twenty-orm/repository/permissions.utils'; import { WorkspaceDeleteQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-delete-query-builder'; import { WorkspaceSoftDeleteQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-soft-delete-query-builder'; import { WorkspaceUpdateQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-update-query-builder'; @@ -50,6 +50,48 @@ export class WorkspaceSelectQueryBuilder< return super.getMany(); } + override getRawOne(): Promise { + this.validatePermissions(); + + return super.getRawOne(); + } + + override getRawMany(): Promise { + this.validatePermissions(); + + return super.getRawMany(); + } + + override getOne(): Promise { + this.validatePermissions(); + + return super.getOne(); + } + + override getOneOrFail(): Promise { + this.validatePermissions(); + + return super.getOneOrFail(); + } + + override getCount(): Promise { + this.validatePermissions(); + + return super.getCount(); + } + + override getExists(): Promise { + this.validatePermissions(); + + return super.getExists(); + } + + override getManyAndCount(): Promise<[T[], number]> { + this.validatePermissions(); + + return super.getManyAndCount(); + } + override update(): WorkspaceUpdateQueryBuilder; override update( diff --git a/packages/twenty-server/src/engine/twenty-orm/repository/workspace-soft-delete-query-builder.ts b/packages/twenty-server/src/engine/twenty-orm/repository/workspace-soft-delete-query-builder.ts index ddaf38012..4be700055 100644 --- a/packages/twenty-server/src/engine/twenty-orm/repository/workspace-soft-delete-query-builder.ts +++ b/packages/twenty-server/src/engine/twenty-orm/repository/workspace-soft-delete-query-builder.ts @@ -4,7 +4,7 @@ import { SoftDeleteQueryBuilder } from 'typeorm/query-builder/SoftDeleteQueryBui import { WorkspaceInternalContext } from 'src/engine/twenty-orm/interfaces/workspace-internal-context.interface'; -import { validateQueryIsPermittedOrThrow } from 'src/engine/twenty-orm/repository/permissions.util'; +import { validateQueryIsPermittedOrThrow } from 'src/engine/twenty-orm/repository/permissions.utils'; import { WorkspaceDeleteQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-delete-query-builder'; import { WorkspaceSelectQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-select-query-builder'; import { WorkspaceUpdateQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-update-query-builder'; diff --git a/packages/twenty-server/src/engine/twenty-orm/repository/workspace-update-query-builder.ts b/packages/twenty-server/src/engine/twenty-orm/repository/workspace-update-query-builder.ts index 3eb54c40c..558511269 100644 --- a/packages/twenty-server/src/engine/twenty-orm/repository/workspace-update-query-builder.ts +++ b/packages/twenty-server/src/engine/twenty-orm/repository/workspace-update-query-builder.ts @@ -3,7 +3,7 @@ import { ObjectLiteral, UpdateQueryBuilder, UpdateResult } from 'typeorm'; import { WorkspaceInternalContext } from 'src/engine/twenty-orm/interfaces/workspace-internal-context.interface'; -import { validateQueryIsPermittedOrThrow } from 'src/engine/twenty-orm/repository/permissions.util'; +import { validateQueryIsPermittedOrThrow } from 'src/engine/twenty-orm/repository/permissions.utils'; import { WorkspaceDeleteQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-delete-query-builder'; import { WorkspaceSelectQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-select-query-builder'; import { WorkspaceSoftDeleteQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-soft-delete-query-builder'; diff --git a/packages/twenty-server/src/engine/twenty-orm/repository/workspace.repository.ts b/packages/twenty-server/src/engine/twenty-orm/repository/workspace.repository.ts index 8140b6a00..45d5d3c7f 100644 --- a/packages/twenty-server/src/engine/twenty-orm/repository/workspace.repository.ts +++ b/packages/twenty-server/src/engine/twenty-orm/repository/workspace.repository.ts @@ -2,7 +2,6 @@ import { ObjectRecordsPermissions } from 'twenty-shared/types'; import { DeepPartial, DeleteResult, - EntityManager, EntitySchema, EntityTarget, FindManyOptions, @@ -27,6 +26,7 @@ import { WorkspaceInternalContext } from 'src/engine/twenty-orm/interfaces/works import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps'; import { getObjectMetadataMapItemByNameSingular } from 'src/engine/metadata-modules/utils/get-object-metadata-map-item-by-name-singular.util'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; import { WorkspaceSelectQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-select-query-builder'; import { WorkspaceEntitiesStorage } from 'src/engine/twenty-orm/storage/workspace-entities.storage'; import { formatData } from 'src/engine/twenty-orm/utils/format-data.util'; @@ -39,10 +39,12 @@ export class WorkspaceRepository< private shouldBypassPermissionChecks: boolean; private featureFlagMap: FeatureFlagMap; private objectRecordsPermissions?: ObjectRecordsPermissions; + declare manager: WorkspaceEntityManager; + constructor( internalContext: WorkspaceInternalContext, target: EntityTarget, - manager: EntityManager, + manager: WorkspaceEntityManager, featureFlagMap: FeatureFlagMap, queryRunner?: QueryRunner, objectRecordsPermissions?: ObjectRecordsPermissions, @@ -53,6 +55,7 @@ export class WorkspaceRepository< this.featureFlagMap = featureFlagMap; this.objectRecordsPermissions = objectRecordsPermissions; this.shouldBypassPermissionChecks = shouldBypassPermissionChecks; + this.manager = manager; } override createQueryBuilder( @@ -87,7 +90,7 @@ export class WorkspaceRepository< */ override async find( options?: FindManyOptions, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise { const manager = entityManager || this.manager; const computedOptions = await this.transformOptions(options); @@ -99,7 +102,7 @@ export class WorkspaceRepository< override async findBy( where: FindOptionsWhere | FindOptionsWhere[], - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise { const manager = entityManager || this.manager; const computedOptions = await this.transformOptions({ where }); @@ -111,7 +114,7 @@ export class WorkspaceRepository< override async findAndCount( options?: FindManyOptions, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise<[T[], number]> { const manager = entityManager || this.manager; const computedOptions = await this.transformOptions(options); @@ -123,7 +126,7 @@ export class WorkspaceRepository< override async findAndCountBy( where: FindOptionsWhere | FindOptionsWhere[], - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise<[T[], number]> { const manager = entityManager || this.manager; const computedOptions = await this.transformOptions({ where }); @@ -138,7 +141,7 @@ export class WorkspaceRepository< override async findOne( options: FindOneOptions, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise { const manager = entityManager || this.manager; const computedOptions = await this.transformOptions(options); @@ -150,7 +153,7 @@ export class WorkspaceRepository< override async findOneBy( where: FindOptionsWhere | FindOptionsWhere[], - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise { const manager = entityManager || this.manager; const computedOptions = await this.transformOptions({ where }); @@ -162,7 +165,7 @@ export class WorkspaceRepository< override async findOneOrFail( options: FindOneOptions, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise { const manager = entityManager || this.manager; const computedOptions = await this.transformOptions(options); @@ -174,7 +177,7 @@ export class WorkspaceRepository< override async findOneByOrFail( where: FindOptionsWhere | FindOptionsWhere[], - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise { const manager = entityManager || this.manager; const computedOptions = await this.transformOptions({ where }); @@ -193,31 +196,31 @@ export class WorkspaceRepository< override save>( entities: U[], options: SaveOptions & { reload: false }, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise; override save>( entities: U[], options?: SaveOptions, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise<(U & T)[]>; override save>( entity: U, options: SaveOptions & { reload: false }, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise; override save>( entity: U, options?: SaveOptions, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise; override async save>( entityOrEntities: U | U[], options?: SaveOptions, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise { const manager = entityManager || this.manager; const formattedEntityOrEntities = await this.formatData(entityOrEntities); @@ -249,19 +252,19 @@ export class WorkspaceRepository< override remove( entities: T[], options?: RemoveOptions, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise; override remove( entity: T, options?: RemoveOptions, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise; override async remove( entityOrEntities: T | T[], options?: RemoveOptions, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise { const manager = entityManager || this.manager; const formattedEntityOrEntities = await this.formatData(entityOrEntities); @@ -287,7 +290,7 @@ export class WorkspaceRepository< | ObjectId | ObjectId[] | FindOptionsWhere, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise { const manager = entityManager || this.manager; @@ -301,31 +304,31 @@ export class WorkspaceRepository< override softRemove>( entities: U[], options: SaveOptions & { reload: false }, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise; override softRemove>( entities: U[], options?: SaveOptions, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise<(U & T)[]>; override softRemove>( entity: U, options: SaveOptions & { reload: false }, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise; override softRemove>( entity: T, options?: SaveOptions, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise; override async softRemove>( entityOrEntities: U | U[], options?: SaveOptions, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise { const manager = entityManager || this.manager; const formattedEntityOrEntities = await this.formatData(entityOrEntities); @@ -362,7 +365,7 @@ export class WorkspaceRepository< | ObjectId | ObjectId[] | FindOptionsWhere, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise { const manager = entityManager || this.manager; @@ -379,31 +382,31 @@ export class WorkspaceRepository< override recover>( entities: U, options: SaveOptions & { reload: false }, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise; override recover>( entities: U, options?: SaveOptions, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise<(U & T)[]>; override recover>( entity: U, options: SaveOptions & { reload: false }, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise; override recover>( entity: U, options?: SaveOptions, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise; override async recover>( entityOrEntities: U | U[], options?: SaveOptions, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise { const manager = entityManager || this.manager; const formattedEntityOrEntities = await this.formatData(entityOrEntities); @@ -440,7 +443,7 @@ export class WorkspaceRepository< | ObjectId | ObjectId[] | FindOptionsWhere, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise { const manager = entityManager || this.manager; @@ -456,12 +459,15 @@ export class WorkspaceRepository< */ override async insert( entity: QueryDeepPartialEntity | QueryDeepPartialEntity[], - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise { const manager = entityManager || this.manager; - const formatedEntity = await this.formatData(entity); - const result = await manager.insert(this.target, formatedEntity); + const formattedEntity = await this.formatData(entity); + const result = await manager.insert(this.target, formattedEntity, { + shouldBypassPermissionChecks: this.shouldBypassPermissionChecks, + objectRecordsPermissions: this.objectRecordsPermissions, + }); const formattedResult = await this.formatResult(result.generatedMaps); return { @@ -486,7 +492,7 @@ export class WorkspaceRepository< | ObjectId[] | FindOptionsWhere, partialEntity: QueryDeepPartialEntity, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise { const manager = entityManager || this.manager; @@ -500,7 +506,7 @@ export class WorkspaceRepository< override async upsert( entityOrEntities: QueryDeepPartialEntity | QueryDeepPartialEntity[], conflictPathsOrOptions: string[] | UpsertOptions, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise { const manager = entityManager || this.manager; @@ -510,6 +516,10 @@ export class WorkspaceRepository< this.target, formattedEntityOrEntities, conflictPathsOrOptions, + { + shouldBypassPermissionChecks: this.shouldBypassPermissionChecks, + objectRecordsPermissions: this.objectRecordsPermissions, + }, ); const formattedResult = await this.formatResult(result.generatedMaps); @@ -526,7 +536,7 @@ export class WorkspaceRepository< */ override async exists( options?: FindManyOptions, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise { const manager = entityManager || this.manager; const computedOptions = await this.transformOptions(options); @@ -536,7 +546,7 @@ export class WorkspaceRepository< override async existsBy( where: FindOptionsWhere | FindOptionsWhere[], - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise { const manager = entityManager || this.manager; const computedOptions = await this.transformOptions({ where }); @@ -549,7 +559,7 @@ export class WorkspaceRepository< */ override async count( options?: FindManyOptions, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise { const manager = entityManager || this.manager; const computedOptions = await this.transformOptions(options); @@ -559,7 +569,7 @@ export class WorkspaceRepository< override async countBy( where: FindOptionsWhere | FindOptionsWhere[], - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise { const manager = entityManager || this.manager; const computedOptions = await this.transformOptions({ where }); @@ -573,7 +583,7 @@ export class WorkspaceRepository< override async sum( columnName: PickKeysByType, where?: FindOptionsWhere | FindOptionsWhere[], - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise { const manager = entityManager || this.manager; const computedOptions = await this.transformOptions({ where }); @@ -584,7 +594,7 @@ export class WorkspaceRepository< override async average( columnName: PickKeysByType, where?: FindOptionsWhere | FindOptionsWhere[], - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise { const manager = entityManager || this.manager; const computedOptions = await this.transformOptions({ where }); @@ -595,7 +605,7 @@ export class WorkspaceRepository< override async minimum( columnName: PickKeysByType, where?: FindOptionsWhere | FindOptionsWhere[], - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise { const manager = entityManager || this.manager; const computedOptions = await this.transformOptions({ where }); @@ -606,7 +616,7 @@ export class WorkspaceRepository< override async maximum( columnName: PickKeysByType, where?: FindOptionsWhere | FindOptionsWhere[], - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise { const manager = entityManager || this.manager; const computedOptions = await this.transformOptions({ where }); @@ -618,7 +628,7 @@ export class WorkspaceRepository< conditions: FindOptionsWhere, propertyPath: string, value: number | string, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise { const manager = entityManager || this.manager; const computedConditions = await this.transformOptions({ @@ -637,7 +647,7 @@ export class WorkspaceRepository< conditions: FindOptionsWhere, propertyPath: string, value: number | string, - entityManager?: EntityManager, + entityManager?: WorkspaceEntityManager, ): Promise { const manager = entityManager || this.manager; const computedConditions = await this.transformOptions({ diff --git a/packages/twenty-server/src/engine/workspace-datasource/workspace-datasource.service.ts b/packages/twenty-server/src/engine/workspace-datasource/workspace-datasource.service.ts index 0e5dc97c2..6b4e87d64 100644 --- a/packages/twenty-server/src/engine/workspace-datasource/workspace-datasource.service.ts +++ b/packages/twenty-server/src/engine/workspace-datasource/workspace-datasource.service.ts @@ -2,9 +2,9 @@ import { Injectable } from '@nestjs/common'; import { DataSource, EntityManager } from 'typeorm'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; import { TypeORMService } from 'src/database/typeorm/typeorm.service'; import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity'; +import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; @Injectable() export class WorkspaceDataSourceService { diff --git a/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/seed-company-with-demo-data.ts b/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/seed-company-with-demo-data.ts index 7e7a6a9f9..3c76815d9 100644 --- a/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/seed-company-with-demo-data.ts +++ b/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/seed-company-with-demo-data.ts @@ -1,13 +1,15 @@ -import { EntityManager } from 'typeorm'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; import { COMPANIES_DEMO } from 'src/engine/workspace-manager/demo-objects-prefill-data/companies-demo.json'; export const seedCompanyWithDemoData = async ( - entityManager: EntityManager, + entityManager: WorkspaceEntityManager, schemaName: string, ) => { await entityManager - .createQueryBuilder() + .createQueryBuilder(undefined, undefined, undefined, { + shouldBypassPermissionChecks: true, + }) .insert() .into(`${schemaName}.company`, [ 'name', diff --git a/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/seed-opportunity-with-demo-data.ts b/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/seed-opportunity-with-demo-data.ts index 8fa5b804d..07fecb14b 100644 --- a/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/seed-opportunity-with-demo-data.ts +++ b/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/seed-opportunity-with-demo-data.ts @@ -1,5 +1,5 @@ +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; import { DEMO_SEED_WORKSPACE_MEMBER_IDS } from 'src/engine/workspace-manager/demo-objects-prefill-data/seed-workspace-member-with-demo-data'; -import { EntityManager } from 'typeorm'; import { v4 } from 'uuid'; const tableName = 'opportunity'; @@ -33,7 +33,7 @@ const generateOpportunities = (companies) => { }; export const seedOpportunityWithDemoData = async ( - entityManager: EntityManager, + entityManager: WorkspaceEntityManager, schemaName: string, ) => { const companiesWithPeople = await entityManager?.query( @@ -46,7 +46,9 @@ export const seedOpportunityWithDemoData = async ( const opportunities = generateOpportunities(companiesWithPeople); await entityManager - .createQueryBuilder() + .createQueryBuilder(undefined, undefined, undefined, { + shouldBypassPermissionChecks: true, + }) .insert() .into(`${schemaName}.${tableName}`, [ 'id', diff --git a/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/seed-person-with-demo-data.ts b/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/seed-person-with-demo-data.ts index e71de5be5..c8ed72a7d 100644 --- a/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/seed-person-with-demo-data.ts +++ b/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/seed-person-with-demo-data.ts @@ -1,9 +1,9 @@ -import { EntityManager } from 'typeorm'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; import { peopleDemo } from 'src/engine/workspace-manager/demo-objects-prefill-data/people-demo.json'; export const seedPersonWithDemoData = async ( - entityManager: EntityManager, + entityManager: WorkspaceEntityManager, schemaName: string, ) => { const companies = await entityManager?.query( @@ -27,7 +27,9 @@ export const seedPersonWithDemoData = async ( })); await entityManager - .createQueryBuilder() + .createQueryBuilder(undefined, undefined, undefined, { + shouldBypassPermissionChecks: true, + }) .insert() .into(`${schemaName}.person`, [ 'nameFirstName', diff --git a/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/seed-workspace-member-with-demo-data.ts b/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/seed-workspace-member-with-demo-data.ts index 7ca69fa9d..9a98e68fa 100644 --- a/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/seed-workspace-member-with-demo-data.ts +++ b/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/seed-workspace-member-with-demo-data.ts @@ -1,6 +1,6 @@ -import { EntityManager } from 'typeorm'; import { DEMO_SEED_USER_IDS } from 'src/database/typeorm-seeds/core/demo/users'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; import { SOURCE_LOCALE } from 'twenty-shared/translations'; export const DEMO_SEED_WORKSPACE_MEMBER_IDS = { @@ -10,11 +10,13 @@ export const DEMO_SEED_WORKSPACE_MEMBER_IDS = { }; export const seedWorkspaceMemberWithDemoData = async ( - entityManager: EntityManager, + entityManager: WorkspaceEntityManager, schemaName: string, ) => { await entityManager - .createQueryBuilder() + .createQueryBuilder(undefined, undefined, undefined, { + shouldBypassPermissionChecks: true, + }) .insert() .into(`${schemaName}.workspaceMember`, [ 'id', diff --git a/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/seed-workspace-with-demo-data.ts b/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/seed-workspace-with-demo-data.ts index f2d889e24..350fc144b 100644 --- a/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/seed-workspace-with-demo-data.ts +++ b/packages/twenty-server/src/engine/workspace-manager/demo-objects-prefill-data/seed-workspace-with-demo-data.ts @@ -1,7 +1,8 @@ -import { DataSource, EntityManager } from 'typeorm'; +import { DataSource } from 'typeorm'; import { seedWorkspaceFavorites } from 'src/database/typeorm-seeds/workspace/favorites'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; import { shouldSeedWorkspaceFavorite } from 'src/engine/utils/should-seed-workspace-favorite'; import { seedCompanyWithDemoData } from 'src/engine/workspace-manager/demo-objects-prefill-data/seed-company-with-demo-data'; import { seedOpportunityWithDemoData } from 'src/engine/workspace-manager/demo-objects-prefill-data/seed-opportunity-with-demo-data'; @@ -28,7 +29,7 @@ export const seedWorkspaceWithDemoData = async ( }, {}); await workspaceDataSource.transaction( - async (entityManager: EntityManager) => { + async (entityManager: WorkspaceEntityManager) => { await seedCompanyWithDemoData(entityManager, schemaName); await seedPersonWithDemoData(entityManager, schemaName); await seedOpportunityWithDemoData(entityManager, schemaName); diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/company.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/company.ts index 9c5591ada..045f7955d 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/company.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/company.ts @@ -1,6 +1,5 @@ -import { EntityManager } from 'typeorm'; - import { FieldActorSource } from 'src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; export const AIRBNB_ID = 'c776ee49-f608-4a77-8cc8-6fe96ae1e43f'; export const QONTO_ID = 'f45ee421-8a3e-4aa5-a1cf-7207cc6754e1'; @@ -9,11 +8,13 @@ export const FIGMA_ID = '9d5bcf43-7d38-4e88-82cb-d6d4ce638bf0'; export const NOTION_ID = '06290608-8bf0-4806-99ae-a715a6a93fad'; export const companyPrefillData = async ( - entityManager: EntityManager, + entityManager: WorkspaceEntityManager, schemaName: string, ) => { await entityManager - .createQueryBuilder() + .createQueryBuilder(undefined, undefined, undefined, { + shouldBypassPermissionChecks: true, + }) .insert() .into(`${schemaName}.company`, [ 'id', diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/create-workspace-views.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/create-workspace-views.ts index 8fc8f1b99..b94e57e49 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/create-workspace-views.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/create-workspace-views.ts @@ -1,10 +1,10 @@ -import { EntityManager } from 'typeorm'; import { v4 } from 'uuid'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; import { ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; export const createWorkspaceViews = async ( - entityManager: EntityManager, + entityManager: WorkspaceEntityManager, schemaName: string, viewDefinitions: ViewDefinition[], ) => { @@ -14,7 +14,9 @@ export const createWorkspaceViews = async ( })); await entityManager - .createQueryBuilder() + .createQueryBuilder(undefined, undefined, undefined, { + shouldBypassPermissionChecks: true, + }) .insert() .into(`${schemaName}.view`, [ 'id', @@ -64,7 +66,9 @@ export const createWorkspaceViews = async ( for (const viewDefinition of viewDefinitionsWithId) { if (viewDefinition.fields && viewDefinition.fields.length > 0) { await entityManager - .createQueryBuilder() + .createQueryBuilder(undefined, undefined, undefined, { + shouldBypassPermissionChecks: true, + }) .insert() .into(`${schemaName}.viewField`, [ 'fieldMetadataId', @@ -89,7 +93,9 @@ export const createWorkspaceViews = async ( if (viewDefinition.filters && viewDefinition.filters.length > 0) { await entityManager - .createQueryBuilder() + .createQueryBuilder(undefined, undefined, undefined, { + shouldBypassPermissionChecks: true, + }) .insert() .into(`${schemaName}.viewFilter`, [ 'fieldMetadataId', @@ -116,7 +122,9 @@ export const createWorkspaceViews = async ( viewDefinition.groups.length > 0 ) { await entityManager - .createQueryBuilder() + .createQueryBuilder(undefined, undefined, undefined, { + shouldBypassPermissionChecks: true, + }) .insert() .into(`${schemaName}.viewGroup`, [ 'fieldMetadataId', diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/person.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/person.ts index 8b2972c6d..127898284 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/person.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/person.ts @@ -1,6 +1,5 @@ -import { EntityManager } from 'typeorm'; - import { FieldActorSource } from 'src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; import { AIRBNB_ID, FIGMA_ID, @@ -11,11 +10,13 @@ import { // FixMe: Is this file a duplicate of src/database/typeorm-seeds/workspace/people.ts export const personPrefillData = async ( - entityManager: EntityManager, + entityManager: WorkspaceEntityManager, schemaName: string, ) => { await entityManager - .createQueryBuilder() + .createQueryBuilder(undefined, undefined, undefined, { + shouldBypassPermissionChecks: true, + }) .insert() .into(`${schemaName}.person`, [ 'nameFirstName', diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/seed-view-with-demo-data.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/seed-view-with-demo-data.ts index 49dc57dfa..2b4a1940c 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/seed-view-with-demo-data.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/seed-view-with-demo-data.ts @@ -1,7 +1,6 @@ -import { EntityManager } from 'typeorm'; - import { ObjectMetadataStandardIdToIdMap } from 'src/engine/metadata-modules/object-metadata/interfaces/object-metadata-standard-id-to-id-map'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; import { createWorkspaceViews } from 'src/engine/workspace-manager/standard-objects-prefill-data/create-workspace-views'; import { seedCompaniesAllView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/companies-all.view'; import { notesAllView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/notes-all.view'; @@ -16,7 +15,7 @@ import { workflowVersionsAllView } from 'src/engine/workspace-manager/standard-o import { workflowsAllView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/workflows-all.view'; export const seedViewWithDemoData = async ( - entityManager: EntityManager, + entityManager: WorkspaceEntityManager, schemaName: string, objectMetadataStandardIdToIdMap: ObjectMetadataStandardIdToIdMap, ) => { diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/standard-objects-prefill-data.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/standard-objects-prefill-data.ts index 68aa1a688..cbd636d14 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/standard-objects-prefill-data.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/standard-objects-prefill-data.ts @@ -1,7 +1,8 @@ -import { DataSource, EntityManager } from 'typeorm'; +import { DataSource } from 'typeorm'; import { seedWorkspaceFavorites } from 'src/database/typeorm-seeds/workspace/favorites'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; import { shouldSeedWorkspaceFavorite } from 'src/engine/utils/should-seed-workspace-favorite'; import { companyPrefillData } from 'src/engine/workspace-manager/standard-objects-prefill-data/company'; import { personPrefillData } from 'src/engine/workspace-manager/standard-objects-prefill-data/person'; @@ -33,28 +34,30 @@ export const standardObjectsPrefillData = async ( return acc; }, {}); - workspaceDataSource.transaction(async (entityManager: EntityManager) => { - await companyPrefillData(entityManager, schemaName); - await personPrefillData(entityManager, schemaName); - const viewDefinitionsWithId = await seedViewWithDemoData( - entityManager, - schemaName, - objectMetadataMap, - ); + workspaceDataSource.transaction( + async (entityManager: WorkspaceEntityManager) => { + await companyPrefillData(entityManager, schemaName); + await personPrefillData(entityManager, schemaName); + const viewDefinitionsWithId = await seedViewWithDemoData( + entityManager, + schemaName, + objectMetadataMap, + ); - await seedWorkspaceFavorites( - viewDefinitionsWithId - .filter( - (view) => - view.key === 'INDEX' && - shouldSeedWorkspaceFavorite( - view.objectMetadataId, - objectMetadataMap, - ), - ) - .map((view) => view.id), - entityManager, - schemaName, - ); - }); + await seedWorkspaceFavorites( + viewDefinitionsWithId + .filter( + (view) => + view.key === 'INDEX' && + shouldSeedWorkspaceFavorite( + view.objectMetadataId, + objectMetadataMap, + ), + ) + .map((view) => view.id), + entityManager, + schemaName, + ); + }, + ); }; diff --git a/packages/twenty-server/src/modules/blocklist/repositories/blocklist.repository.ts b/packages/twenty-server/src/modules/blocklist/repositories/blocklist.repository.ts index c6d6ddb21..e8f3f05b7 100644 --- a/packages/twenty-server/src/modules/blocklist/repositories/blocklist.repository.ts +++ b/packages/twenty-server/src/modules/blocklist/repositories/blocklist.repository.ts @@ -1,7 +1,5 @@ import { Injectable } from '@nestjs/common'; -import { EntityManager } from 'typeorm'; - import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; import { BlocklistWorkspaceEntity } from 'src/modules/blocklist/standard-objects/blocklist.workspace-entity'; @@ -14,7 +12,6 @@ export class BlocklistRepository { public async getById( id: string, workspaceId: string, - transactionManager?: EntityManager, ): Promise { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); @@ -24,7 +21,6 @@ export class BlocklistRepository { `SELECT * FROM ${dataSourceSchema}."blocklist" WHERE "id" = $1`, [id], workspaceId, - transactionManager, ); if (!blocklistItems || blocklistItems.length === 0) { @@ -37,7 +33,6 @@ export class BlocklistRepository { public async getByWorkspaceMemberId( workspaceMemberId: string, workspaceId: string, - transactionManager?: EntityManager, ): Promise { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); @@ -46,7 +41,6 @@ export class BlocklistRepository { `SELECT * FROM ${dataSourceSchema}."blocklist" WHERE "workspaceMemberId" = $1`, [workspaceMemberId], workspaceId, - transactionManager, ); } } diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/services/calendar-save-events.service.ts b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/services/calendar-save-events.service.ts index 7552722e0..d393220f7 100644 --- a/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/services/calendar-save-events.service.ts +++ b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/services/calendar-save-events.service.ts @@ -6,6 +6,7 @@ import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decora import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service'; import { FieldActorSource } from 'src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; import { injectIdsInCalendarEvents } from 'src/modules/calendar/calendar-event-import-manager/utils/inject-ids-in-calendar-events.util'; import { CalendarEventParticipantService } from 'src/modules/calendar/calendar-event-participant-manager/services/calendar-event-participant.service'; @@ -113,71 +114,73 @@ export class CalendarSaveEventsService { const workspaceDataSource = await this.twentyORMManager.getDatasource(); - await workspaceDataSource?.transaction(async (transactionManager) => { - await calendarEventRepository.save( - eventsToSave.map( - (calendarEvent) => - ({ - id: calendarEvent.id, - iCalUID: calendarEvent.iCalUID, - title: calendarEvent.title, - description: calendarEvent.description, - startsAt: calendarEvent.startsAt, - endsAt: calendarEvent.endsAt, - location: calendarEvent.location, - isFullDay: calendarEvent.isFullDay, - isCanceled: calendarEvent.isCanceled, - conferenceSolution: calendarEvent.conferenceSolution, - conferenceLink: { - primaryLinkLabel: calendarEvent.conferenceLinkLabel, - primaryLinkUrl: calendarEvent.conferenceLinkUrl, - }, - externalCreatedAt: calendarEvent.externalCreatedAt, - externalUpdatedAt: calendarEvent.externalUpdatedAt, - }) satisfies DeepPartial, - ), - {}, - transactionManager, - ); + await workspaceDataSource?.transaction( + async (transactionManager: WorkspaceEntityManager) => { + await calendarEventRepository.save( + eventsToSave.map( + (calendarEvent) => + ({ + id: calendarEvent.id, + iCalUID: calendarEvent.iCalUID, + title: calendarEvent.title, + description: calendarEvent.description, + startsAt: calendarEvent.startsAt, + endsAt: calendarEvent.endsAt, + location: calendarEvent.location, + isFullDay: calendarEvent.isFullDay, + isCanceled: calendarEvent.isCanceled, + conferenceSolution: calendarEvent.conferenceSolution, + conferenceLink: { + primaryLinkLabel: calendarEvent.conferenceLinkLabel, + primaryLinkUrl: calendarEvent.conferenceLinkUrl, + }, + externalCreatedAt: calendarEvent.externalCreatedAt, + externalUpdatedAt: calendarEvent.externalUpdatedAt, + }) satisfies DeepPartial, + ), + {}, + transactionManager, + ); - await calendarEventRepository.save( - eventsToUpdate.map( - (calendarEvent) => - ({ - id: calendarEvent.id, - iCalUID: calendarEvent.iCalUID, - title: calendarEvent.title, - description: calendarEvent.description, - startsAt: calendarEvent.startsAt, - endsAt: calendarEvent.endsAt, - location: calendarEvent.location, - isFullDay: calendarEvent.isFullDay, - isCanceled: calendarEvent.isCanceled, - conferenceSolution: calendarEvent.conferenceSolution, - conferenceLink: { - primaryLinkLabel: calendarEvent.conferenceLinkLabel, - primaryLinkUrl: calendarEvent.conferenceLinkUrl, - }, - externalCreatedAt: calendarEvent.externalCreatedAt, - externalUpdatedAt: calendarEvent.externalUpdatedAt, - }) satisfies DeepPartial, - ), - {}, - transactionManager, - ); + await calendarEventRepository.save( + eventsToUpdate.map( + (calendarEvent) => + ({ + id: calendarEvent.id, + iCalUID: calendarEvent.iCalUID, + title: calendarEvent.title, + description: calendarEvent.description, + startsAt: calendarEvent.startsAt, + endsAt: calendarEvent.endsAt, + location: calendarEvent.location, + isFullDay: calendarEvent.isFullDay, + isCanceled: calendarEvent.isCanceled, + conferenceSolution: calendarEvent.conferenceSolution, + conferenceLink: { + primaryLinkLabel: calendarEvent.conferenceLinkLabel, + primaryLinkUrl: calendarEvent.conferenceLinkUrl, + }, + externalCreatedAt: calendarEvent.externalCreatedAt, + externalUpdatedAt: calendarEvent.externalUpdatedAt, + }) satisfies DeepPartial, + ), + {}, + transactionManager, + ); - await calendarChannelEventAssociationRepository.save( - calendarChannelEventAssociationsToSave, - {}, - transactionManager, - ); + await calendarChannelEventAssociationRepository.save( + calendarChannelEventAssociationsToSave, + {}, + transactionManager, + ); - await this.calendarEventParticipantService.upsertAndDeleteCalendarEventParticipants( - participantsToSave, - participantsToUpdate, - transactionManager, - ); - }); + await this.calendarEventParticipantService.upsertAndDeleteCalendarEventParticipants( + participantsToSave, + participantsToUpdate, + transactionManager, + ); + }, + ); if (calendarChannel.isContactAutoCreationEnabled) { await this.messageQueueService.add( diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/services/calendar-event-participant.service.ts b/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/services/calendar-event-participant.service.ts index cc71ebf82..bb190882d 100644 --- a/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/services/calendar-event-participant.service.ts +++ b/packages/twenty-server/src/modules/calendar/calendar-event-participant-manager/services/calendar-event-participant.service.ts @@ -4,6 +4,7 @@ import { isDefined } from 'class-validator'; import differenceWith from 'lodash.differencewith'; import { Any } from 'typeorm'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity'; import { CalendarEventParticipantWithCalendarEventId } from 'src/modules/calendar/common/types/calendar-event'; @@ -19,7 +20,7 @@ export class CalendarEventParticipantService { public async upsertAndDeleteCalendarEventParticipants( participantsToSave: CalendarEventParticipantWithCalendarEventId[], participantsToUpdate: CalendarEventParticipantWithCalendarEventId[], - transactionManager?: any, + transactionManager?: WorkspaceEntityManager, ): Promise { const calendarEventParticipantRepository = await this.twentyORMManager.getRepository( diff --git a/packages/twenty-server/src/modules/contact-creation-manager/services/create-company-and-contact.service.ts b/packages/twenty-server/src/modules/contact-creation-manager/services/create-company-and-contact.service.ts index 2b3abe1ae..8f1b4be90 100644 --- a/packages/twenty-server/src/modules/contact-creation-manager/services/create-company-and-contact.service.ts +++ b/packages/twenty-server/src/modules/contact-creation-manager/services/create-company-and-contact.service.ts @@ -3,7 +3,7 @@ import { InjectRepository } from '@nestjs/typeorm'; import chunk from 'lodash.chunk'; import compact from 'lodash.compact'; -import { Any, EntityManager, Repository } from 'typeorm'; +import { Any, Repository } from 'typeorm'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; import { ExceptionHandlerService } from 'src/engine/core-modules/exception-handler/exception-handler.service'; @@ -45,7 +45,6 @@ export class CreateCompanyAndContactService { contactsToCreate: Contact[], workspaceId: string, source: FieldActorSource, - transactionManager?: EntityManager, ): Promise[]> { if (!contactsToCreate || contactsToCreate.length === 0) { return []; @@ -61,10 +60,7 @@ export class CreateCompanyAndContactService { ); const workspaceMembers = - await this.workspaceMemberRepository.getAllByWorkspaceId( - workspaceId, - transactionManager, - ); + await this.workspaceMemberRepository.getAllByWorkspaceId(workspaceId); const contactsToCreateFromOtherCompanies = filterOutSelfAndContactsFromCompanyOrWorkspace( @@ -137,7 +133,6 @@ export class CreateCompanyAndContactService { const companiesObject = await this.createCompaniesService.createCompanies( workDomainNamesToCreateFormatted, workspaceId, - transactionManager, ); const formattedContactsToCreate = @@ -158,7 +153,6 @@ export class CreateCompanyAndContactService { return this.createContactService.createPeople( formattedContactsToCreate, workspaceId, - transactionManager, ); } diff --git a/packages/twenty-server/src/modules/contact-creation-manager/services/create-company.service.ts b/packages/twenty-server/src/modules/contact-creation-manager/services/create-company.service.ts index cf4ce4d8f..ac407994f 100644 --- a/packages/twenty-server/src/modules/contact-creation-manager/services/create-company.service.ts +++ b/packages/twenty-server/src/modules/contact-creation-manager/services/create-company.service.ts @@ -4,7 +4,7 @@ import axios, { AxiosInstance } from 'axios'; import uniqBy from 'lodash.uniqby'; import { TWENTY_COMPANIES_BASE_URL } from 'twenty-shared/constants'; import { ConnectedAccountProvider } from 'twenty-shared/types'; -import { DeepPartial, EntityManager, ILike } from 'typeorm'; +import { DeepPartial, ILike } from 'typeorm'; import { FieldActorSource } from 'src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type'; import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; @@ -37,7 +37,6 @@ export class CreateCompanyService { async createCompanies( companies: CompanyToCreate[], workspaceId: string, - transactionManager?: EntityManager, ): Promise<{ [domainName: string]: string; }> { @@ -63,12 +62,9 @@ export class CreateCompanyService { })); // Find existing companies - const existingCompanies = await companyRepository.find( - { - where: conditions, - }, - transactionManager, - ); + const existingCompanies = await companyRepository.find({ + where: conditions, + }); const existingCompanyIdsMap = this.createCompanyMap(existingCompanies); // Filter out companies that already exist @@ -87,10 +83,8 @@ export class CreateCompanyService { } // Retrieve the last company position - let lastCompanyPosition = await this.getLastCompanyPosition( - companyRepository, - transactionManager, - ); + let lastCompanyPosition = + await this.getLastCompanyPosition(companyRepository); const newCompaniesData = await Promise.all( newCompaniesToCreate.map((company) => this.prepareCompanyData(company, ++lastCompanyPosition), @@ -156,12 +150,10 @@ export class CreateCompanyService { private async getLastCompanyPosition( companyRepository: WorkspaceRepository, - transactionManager?: EntityManager, ): Promise { const lastCompanyPosition = await companyRepository.maximum( 'position', undefined, - transactionManager, ); return lastCompanyPosition ?? 0; diff --git a/packages/twenty-server/src/modules/contact-creation-manager/services/create-contact.service.ts b/packages/twenty-server/src/modules/contact-creation-manager/services/create-contact.service.ts index 280333e51..31c3dbc58 100644 --- a/packages/twenty-server/src/modules/contact-creation-manager/services/create-contact.service.ts +++ b/packages/twenty-server/src/modules/contact-creation-manager/services/create-contact.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@nestjs/common'; import { ConnectedAccountProvider } from 'twenty-shared/types'; -import { DeepPartial, EntityManager } from 'typeorm'; +import { DeepPartial } from 'typeorm'; import { v4 } from 'uuid'; import { FieldActorSource } from 'src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type'; @@ -74,7 +74,6 @@ export class CreateContactService { public async createPeople( contactsToCreate: ContactToCreate[], workspaceId: string, - transactionManager?: EntityManager, ): Promise[]> { if (contactsToCreate.length === 0) return []; @@ -87,31 +86,23 @@ export class CreateContactService { }, ); - const lastPersonPosition = await this.getLastPersonPosition( - personRepository, - transactionManager, - ); + const lastPersonPosition = + await this.getLastPersonPosition(personRepository); const formattedContacts = this.formatContacts( contactsToCreate, lastPersonPosition, ); - return personRepository.save( - formattedContacts, - undefined, - transactionManager, - ); + return personRepository.save(formattedContacts, undefined); } private async getLastPersonPosition( personRepository: WorkspaceRepository, - transactionManager?: EntityManager, ): Promise { const lastPersonPosition = await personRepository.maximum( 'position', undefined, - transactionManager, ); return lastPersonPosition ?? 0; diff --git a/packages/twenty-server/src/modules/match-participant/match-participant.service.ts b/packages/twenty-server/src/modules/match-participant/match-participant.service.ts index fd5af4a12..93184dd58 100644 --- a/packages/twenty-server/src/modules/match-participant/match-participant.service.ts +++ b/packages/twenty-server/src/modules/match-participant/match-participant.service.ts @@ -1,7 +1,8 @@ import { Injectable } from '@nestjs/common'; -import { Any, EntityManager, Equal } from 'typeorm'; +import { Any, Equal } from 'typeorm'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; import { ScopedWorkspaceContextFactory } from 'src/engine/twenty-orm/factories/scoped-workspace-context.factory'; import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; import { WorkspaceEventEmitter } from 'src/engine/workspace-event-emitter/workspace-event-emitter'; @@ -39,7 +40,7 @@ export class MatchParticipantService< public async matchParticipants( participants: ParticipantWorkspaceEntity[], objectMetadataName: 'messageParticipant' | 'calendarEventParticipant', - transactionManager?: EntityManager, + transactionManager?: WorkspaceEntityManager, ) { const participantRepository = await this.getParticipantRepository(objectMetadataName); diff --git a/packages/twenty-server/src/modules/messaging/message-cleaner/services/messaging-message-cleaner.service.ts b/packages/twenty-server/src/modules/messaging/message-cleaner/services/messaging-message-cleaner.service.ts index 751504050..ddb7f038f 100644 --- a/packages/twenty-server/src/modules/messaging/message-cleaner/services/messaging-message-cleaner.service.ts +++ b/packages/twenty-server/src/modules/messaging/message-cleaner/services/messaging-message-cleaner.service.ts @@ -1,7 +1,8 @@ import { Injectable } from '@nestjs/common'; -import { EntityManager, IsNull } from 'typeorm'; +import { IsNull } from 'typeorm'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; import { MessageThreadWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-thread.workspace-entity'; import { MessageWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message.workspace-entity'; @@ -24,75 +25,77 @@ export class MessagingMessageCleanerService { const workspaceDataSource = await this.twentyORMManager.getDatasource(); - await workspaceDataSource.transaction(async (transactionManager) => { - await deleteUsingPagination( - workspaceId, - 500, - async ( - limit: number, - offset: number, - workspaceId: string, - transactionManager: EntityManager, - ) => { - const nonAssociatedMessages = await messageRepository.find( - { - where: { - messageChannelMessageAssociations: { - id: IsNull(), + await workspaceDataSource.transaction( + async (transactionManager: WorkspaceEntityManager) => { + await deleteUsingPagination( + workspaceId, + 500, + async ( + limit: number, + offset: number, + _workspaceId: string, + transactionManager: WorkspaceEntityManager, + ) => { + const nonAssociatedMessages = await messageRepository.find( + { + where: { + messageChannelMessageAssociations: { + id: IsNull(), + }, }, + take: limit, + skip: offset, + relations: ['messageChannelMessageAssociations'], }, - take: limit, - skip: offset, - relations: ['messageChannelMessageAssociations'], - }, - transactionManager, - ); + transactionManager, + ); - return nonAssociatedMessages.map(({ id }) => id); - }, - async ( - ids: string[], - workspaceId: string, - transactionManager?: EntityManager, - ) => { - await messageRepository.delete(ids, transactionManager); - }, - transactionManager, - ); + return nonAssociatedMessages.map(({ id }) => id); + }, + async ( + ids: string[], + workspaceId: string, + transactionManager?: WorkspaceEntityManager, + ) => { + await messageRepository.delete(ids, transactionManager); + }, + transactionManager, + ); - await deleteUsingPagination( - workspaceId, - 500, - async ( - limit: number, - offset: number, - workspaceId: string, - transactionManager?: EntityManager, - ) => { - const orphanThreads = await messageThreadRepository.find( - { - where: { - messages: { - id: IsNull(), + await deleteUsingPagination( + workspaceId, + 500, + async ( + limit: number, + offset: number, + _workspaceId: string, + transactionManager?: WorkspaceEntityManager, + ) => { + const orphanThreads = await messageThreadRepository.find( + { + where: { + messages: { + id: IsNull(), + }, }, + take: limit, + skip: offset, }, - take: limit, - skip: offset, - }, - transactionManager, - ); + transactionManager, + ); - return orphanThreads.map(({ id }) => id); - }, - async ( - ids: string[], - workspaceId: string, - transactionManager?: EntityManager, - ) => { - await messageThreadRepository.delete(ids, transactionManager); - }, - transactionManager, - ); - }); + return orphanThreads.map(({ id }) => id); + }, + async ( + ids: string[], + _workspaceId: string, + transactionManager?: WorkspaceEntityManager, + ) => { + await messageThreadRepository.delete(ids, transactionManager); + }, + transactionManager, + ); + }, + ); } } diff --git a/packages/twenty-server/src/modules/messaging/message-cleaner/utils/delete-using-pagination.util.ts b/packages/twenty-server/src/modules/messaging/message-cleaner/utils/delete-using-pagination.util.ts index e650ec18d..a883cfd42 100644 --- a/packages/twenty-server/src/modules/messaging/message-cleaner/utils/delete-using-pagination.util.ts +++ b/packages/twenty-server/src/modules/messaging/message-cleaner/utils/delete-using-pagination.util.ts @@ -1,4 +1,4 @@ -import { EntityManager } from 'typeorm'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; export const deleteUsingPagination = async ( workspaceId: string, @@ -7,14 +7,14 @@ export const deleteUsingPagination = async ( limit: number, offset: number, workspaceId: string, - transactionManager?: EntityManager, + transactionManager?: WorkspaceEntityManager, ) => Promise, deleter: ( ids: string[], workspaceId: string, - transactionManager?: EntityManager, + transactionManager?: WorkspaceEntityManager, ) => Promise, - transactionManager?: EntityManager, + transactionManager?: WorkspaceEntityManager, ) => { let hasMoreData = true; diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/services/messaging-message.service.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/services/messaging-message.service.ts index 6540b3c6b..1a7a398fe 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/services/messaging-message.service.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/services/messaging-message.service.ts @@ -1,8 +1,8 @@ import { Injectable } from '@nestjs/common'; -import { EntityManager } from 'typeorm'; import { v4 } from 'uuid'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity'; import { MessageThreadWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-thread.workspace-entity'; @@ -16,7 +16,7 @@ export class MessagingMessageService { public async saveMessagesWithinTransaction( messages: MessageWithParticipants[], messageChannelId: string, - transactionManager: EntityManager, + transactionManager: WorkspaceEntityManager, ): Promise<{ createdMessages: Partial[]; messageExternalIdsAndIdsMap: Map; diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/services/messaging-save-messages-and-enqueue-contact-creation.service.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/services/messaging-save-messages-and-enqueue-contact-creation.service.ts index 4c1adcd3e..c0d2e169d 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/services/messaging-save-messages-and-enqueue-contact-creation.service.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/services/messaging-save-messages-and-enqueue-contact-creation.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; -import { EntityManager, Repository } from 'typeorm'; +import { Repository } from 'typeorm'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator'; @@ -9,6 +9,7 @@ import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queu import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service'; import { FieldActorSource } from 'src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; import { WorkspaceEventEmitter } from 'src/engine/workspace-event-emitter/workspace-event-emitter'; import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; @@ -55,7 +56,7 @@ export class MessagingSaveMessagesAndEnqueueContactCreationService { const createdMessagesWithParticipants = await workspaceDataSource?.transaction( - async (transactionManager: EntityManager) => { + async (transactionManager: WorkspaceEntityManager) => { const { messageExternalIdsAndIdsMap, createdMessages } = await this.messageService.saveMessagesWithinTransaction( messagesToSave, diff --git a/packages/twenty-server/src/modules/messaging/message-participant-manager/services/messaging-message-participant.service.ts b/packages/twenty-server/src/modules/messaging/message-participant-manager/services/messaging-message-participant.service.ts index 4ccf40c39..c8c88c939 100644 --- a/packages/twenty-server/src/modules/messaging/message-participant-manager/services/messaging-message-participant.service.ts +++ b/packages/twenty-server/src/modules/messaging/message-participant-manager/services/messaging-message-participant.service.ts @@ -1,7 +1,6 @@ import { Injectable } from '@nestjs/common'; -import { EntityManager } from 'typeorm'; - +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; import { MatchParticipantService } from 'src/modules/match-participant/match-participant.service'; import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity'; @@ -16,7 +15,7 @@ export class MessagingMessageParticipantService { public async saveMessageParticipants( participants: ParticipantWithMessageId[], - transactionManager?: EntityManager, + transactionManager?: WorkspaceEntityManager, ): Promise { const messageParticipantRepository = await this.twentyORMManager.getRepository( diff --git a/packages/twenty-server/src/modules/timeline/repositiories/timeline-activity.repository.ts b/packages/twenty-server/src/modules/timeline/repositiories/timeline-activity.repository.ts index cae34c1d9..e42ff70b2 100644 --- a/packages/twenty-server/src/modules/timeline/repositiories/timeline-activity.repository.ts +++ b/packages/twenty-server/src/modules/timeline/repositiories/timeline-activity.repository.ts @@ -1,7 +1,5 @@ import { Injectable } from '@nestjs/common'; -import { EntityManager } from 'typeorm'; - import { ObjectRecord } from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface'; import { objectRecordDiffMerge } from 'src/engine/core-modules/event-emitter/utils/object-record-diff-merge'; @@ -159,7 +157,6 @@ export class TimelineActivityRepository { linkedObjectMetadataId: string | undefined; }[], workspaceId: string, - transactionManager?: EntityManager, ) { if (activities.length === 0) { return; @@ -191,7 +188,6 @@ export class TimelineActivityRepository { ]) .flat(), workspaceId, - transactionManager, ); } } diff --git a/packages/twenty-server/src/modules/workflow/workflow-trigger/automated-trigger/automated-trigger.workspace-service.ts b/packages/twenty-server/src/modules/workflow/workflow-trigger/automated-trigger/automated-trigger.workspace-service.ts index a4f9f48b9..4ebcf0dcf 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-trigger/automated-trigger/automated-trigger.workspace-service.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-trigger/automated-trigger/automated-trigger.workspace-service.ts @@ -1,14 +1,13 @@ import { Injectable } from '@nestjs/common'; -import { EntityManager } from 'typeorm'; - +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; -import { WorkflowEventListenerWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-event-listener.workspace-entity'; import { - AutomatedTriggerType, AutomatedTriggerSettings, + AutomatedTriggerType, WorkflowAutomatedTriggerWorkspaceEntity, } from 'src/modules/workflow/common/standard-objects/workflow-automated-trigger.workspace-entity'; +import { WorkflowEventListenerWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-event-listener.workspace-entity'; @Injectable() export class AutomatedTriggerWorkspaceService { @@ -21,7 +20,7 @@ export class AutomatedTriggerWorkspaceService { settings, }: { workflowId: string; - manager: EntityManager; + manager: WorkspaceEntityManager; type: AutomatedTriggerType; settings: AutomatedTriggerSettings; }) { @@ -68,7 +67,7 @@ export class AutomatedTriggerWorkspaceService { manager, }: { workflowId: string; - manager: EntityManager; + manager: WorkspaceEntityManager; }) { // Todo: remove workflowEventListenerRepository updates when data are migrated to workflowAutomatedTrigger const workflowEventListenerRepository = diff --git a/packages/twenty-server/src/modules/workflow/workflow-trigger/workspace-services/workflow-trigger.workspace-service.ts b/packages/twenty-server/src/modules/workflow/workflow-trigger/workspace-services/workflow-trigger.workspace-service.ts index a3b25bc93..3607a5b9c 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-trigger/workspace-services/workflow-trigger.workspace-service.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-trigger/workspace-services/workflow-trigger.workspace-service.ts @@ -1,15 +1,17 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; -import { EntityManager, Repository } from 'typeorm'; +import { Repository } from 'typeorm'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; import { ActorMetadata } from 'src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; import { ScopedWorkspaceContextFactory } from 'src/engine/twenty-orm/factories/scoped-workspace-context.factory'; import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; import { WorkspaceEventEmitter } from 'src/engine/workspace-event-emitter/workspace-event-emitter'; +import { AutomatedTriggerType } from 'src/modules/workflow/common/standard-objects/workflow-automated-trigger.workspace-entity'; import { WorkflowVersionStatus, WorkflowVersionWorkspaceEntity, @@ -20,6 +22,7 @@ import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/work import { WorkflowRunnerWorkspaceService } from 'src/modules/workflow/workflow-runner/workspace-services/workflow-runner.workspace-service'; import { WORKFLOW_VERSION_STATUS_UPDATED } from 'src/modules/workflow/workflow-status/constants/workflow-version-status-updated.constants'; import { WorkflowVersionStatusUpdate } from 'src/modules/workflow/workflow-status/jobs/workflow-statuses-update.job'; +import { AutomatedTriggerWorkspaceService } from 'src/modules/workflow/workflow-trigger/automated-trigger/automated-trigger.workspace-service'; import { WorkflowTriggerException, WorkflowTriggerExceptionCode, @@ -28,8 +31,6 @@ import { WorkflowTriggerType } from 'src/modules/workflow/workflow-trigger/types import { assertVersionCanBeActivated } from 'src/modules/workflow/workflow-trigger/utils/assert-version-can-be-activated.util'; import { computeCronPatternFromSchedule } from 'src/modules/workflow/workflow-trigger/utils/compute-cron-pattern-from-schedule'; import { assertNever } from 'src/utils/assert'; -import { AutomatedTriggerWorkspaceService } from 'src/modules/workflow/workflow-trigger/automated-trigger/automated-trigger.workspace-service'; -import { AutomatedTriggerType } from 'src/modules/workflow/common/standard-objects/workflow-automated-trigger.workspace-entity'; @Injectable() export class WorkflowTriggerWorkspaceService { @@ -174,7 +175,7 @@ export class WorkflowTriggerWorkspaceService { workflowVersion: WorkflowVersionWorkspaceEntity, workflowRepository: WorkspaceRepository, workflowVersionRepository: WorkspaceRepository, - manager: EntityManager, + manager: WorkspaceEntityManager, ) { if ( workflow.lastPublishedVersionId && @@ -207,7 +208,7 @@ export class WorkflowTriggerWorkspaceService { private async performDeactivationSteps( workflowVersionId: string, workflowVersionRepository: WorkspaceRepository, - manager: EntityManager, + manager: WorkspaceEntityManager, ) { const workflowVersionNullable = await workflowVersionRepository.findOne({ where: { id: workflowVersionId }, @@ -234,7 +235,7 @@ export class WorkflowTriggerWorkspaceService { private async setActiveVersionStatus( workflowVersion: WorkflowVersionWorkspaceEntity, workflowVersionRepository: WorkspaceRepository, - manager: EntityManager, + manager: WorkspaceEntityManager, ) { const activeWorkflowVersions = await workflowVersionRepository.find( { @@ -269,7 +270,7 @@ export class WorkflowTriggerWorkspaceService { private async setDeactivatedVersionStatus( workflowVersion: WorkflowVersionWorkspaceEntity, workflowVersionRepository: WorkspaceRepository, - manager: EntityManager, + manager: WorkspaceEntityManager, ) { if (workflowVersion.status !== WorkflowVersionStatus.ACTIVE) { throw new WorkflowTriggerException( @@ -296,7 +297,7 @@ export class WorkflowTriggerWorkspaceService { newPublishedVersionId: string, workflowRepository: WorkspaceRepository, workflowVersionRepository: WorkspaceRepository, - manager: EntityManager, + manager: WorkspaceEntityManager, ) { if (workflow.lastPublishedVersionId === newPublishedVersionId) { return; @@ -319,7 +320,7 @@ export class WorkflowTriggerWorkspaceService { private async enableTrigger( workflowVersion: WorkflowVersionWorkspaceEntity, - manager: EntityManager, + manager: WorkspaceEntityManager, ) { assertWorkflowVersionTriggerIsDefined(workflowVersion); @@ -359,7 +360,7 @@ export class WorkflowTriggerWorkspaceService { private async disableTrigger( workflowVersion: WorkflowVersionWorkspaceEntity, - manager: EntityManager, + manager: WorkspaceEntityManager, ) { assertWorkflowVersionTriggerIsDefined(workflowVersion); diff --git a/packages/twenty-server/src/modules/workspace-member/repositories/workspace-member.repository.ts b/packages/twenty-server/src/modules/workspace-member/repositories/workspace-member.repository.ts index 0d3b5acc3..04c5411e4 100644 --- a/packages/twenty-server/src/modules/workspace-member/repositories/workspace-member.repository.ts +++ b/packages/twenty-server/src/modules/workspace-member/repositories/workspace-member.repository.ts @@ -1,7 +1,5 @@ import { Injectable, NotFoundException } from '@nestjs/common'; -import { EntityManager } from 'typeorm'; - import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; @@ -50,7 +48,6 @@ export class WorkspaceMemberRepository { public async getAllByWorkspaceId( workspaceId: string, - transactionManager?: EntityManager, ): Promise { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); @@ -60,7 +57,6 @@ export class WorkspaceMemberRepository { `SELECT * FROM ${dataSourceSchema}."workspaceMember"`, [], workspaceId, - transactionManager, ); return workspaceMembers; diff --git a/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/create-one-object-records-permissions.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/create-one-object-records-permissions.integration-spec.ts index 9565f3089..56f57c16c 100644 --- a/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/create-one-object-records-permissions.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/create-one-object-records-permissions.integration-spec.ts @@ -2,9 +2,12 @@ import { randomUUID } from 'node:crypto'; import { PERSON_GQL_FIELDS } from 'test/integration/constants/person-gql-fields.constants'; import { createOneOperationFactory } from 'test/integration/graphql/utils/create-one-operation-factory.util'; +import { makeGraphqlAPIRequestWithApiKey } from 'test/integration/graphql/utils/make-graphql-api-request-with-api-key.util'; import { makeGraphqlAPIRequestWithGuestRole } from 'test/integration/graphql/utils/make-graphql-api-request-with-guest-role.util'; import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; +import { updateFeatureFlagFactory } from 'test/integration/graphql/utils/update-feature-flag-factory.util'; +import { SEED_APPLE_WORKSPACE_ID } from 'src/database/typeorm-seeds/core/workspaces'; import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception'; @@ -48,79 +51,79 @@ describe('createOneObjectRecordsPermissions', () => { }); }); - // describe('permissions V2 enabled', () => { - // beforeAll(async () => { - // const enablePermissionsQuery = updateFeatureFlagFactory( - // SEED_APPLE_WORKSPACE_ID, - // 'IsPermissionsV2Enabled', - // true, - // ); + describe('permissions V2 enabled', () => { + beforeAll(async () => { + const enablePermissionsQuery = updateFeatureFlagFactory( + SEED_APPLE_WORKSPACE_ID, + 'IsPermissionsV2Enabled', + true, + ); - // await makeGraphqlAPIRequest(enablePermissionsQuery); - // }); + await makeGraphqlAPIRequest(enablePermissionsQuery); + }); - // afterAll(async () => { - // const disablePermissionsQuery = updateFeatureFlagFactory( - // SEED_APPLE_WORKSPACE_ID, - // 'IsPermissionsV2Enabled', - // false, - // ); + afterAll(async () => { + const disablePermissionsQuery = updateFeatureFlagFactory( + SEED_APPLE_WORKSPACE_ID, + 'IsPermissionsV2Enabled', + false, + ); - // await makeGraphqlAPIRequest(disablePermissionsQuery); - // }); + await makeGraphqlAPIRequest(disablePermissionsQuery); + }); - // it('should throw a permission error when user does not have permission (guest role)', async () => { - // const graphqlOperation = createOneOperationFactory({ - // objectMetadataSingularName: 'person', - // gqlFields: PERSON_GQL_FIELDS, - // data: { - // id: randomUUID(), - // }, - // }); + it('should throw a permission error when user does not have permission (guest role)', async () => { + const graphqlOperation = createOneOperationFactory({ + objectMetadataSingularName: 'person', + gqlFields: PERSON_GQL_FIELDS, + data: { + id: randomUUID(), + }, + }); - // const response = - // await makeGraphqlAPIRequestWithGuestRole(graphqlOperation); + const response = + await makeGraphqlAPIRequestWithGuestRole(graphqlOperation); - // expect(response.body.data).toStrictEqual({ createPerson: null }); - // expect(response.body.errors).toBeDefined(); - // expect(response.body.errors[0].message).toBe( - // PermissionsExceptionMessage.PERMISSION_DENIED, - // ); - // expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN); - // }); + expect(response.body.data).toStrictEqual({ createPerson: null }); + expect(response.body.errors).toBeDefined(); + expect(response.body.errors[0].message).toBe( + PermissionsExceptionMessage.PERMISSION_DENIED, + ); + expect(response.body.errors[0].extensions.code).toBe(ErrorCode.FORBIDDEN); + }); - // it('should create an object record when user has permission (admin role)', async () => { - // const personId = randomUUID(); - // const graphqlOperation = createOneOperationFactory({ - // objectMetadataSingularName: 'person', - // gqlFields: PERSON_GQL_FIELDS, - // data: { - // id: personId, - // }, - // }); + it('should create an object record when user has permission (admin role)', async () => { + const personId = randomUUID(); + const graphqlOperation = createOneOperationFactory({ + objectMetadataSingularName: 'person', + gqlFields: PERSON_GQL_FIELDS, + data: { + id: personId, + }, + }); - // const response = await makeGraphqlAPIRequest(graphqlOperation); + const response = await makeGraphqlAPIRequest(graphqlOperation); - // expect(response.body.data).toBeDefined(); - // expect(response.body.data.createPerson).toBeDefined(); - // expect(response.body.data.createPerson.id).toBe(personId); - // }); + expect(response.body.data).toBeDefined(); + expect(response.body.data.createPerson).toBeDefined(); + expect(response.body.data.createPerson.id).toBe(personId); + }); - // it('should create an object record when executed by api key', async () => { - // const personId = randomUUID(); - // const graphqlOperation = createOneOperationFactory({ - // objectMetadataSingularName: 'person', - // gqlFields: PERSON_GQL_FIELDS, - // data: { - // id: personId, - // }, - // }); + it('should create an object record when executed by api key', async () => { + const personId = randomUUID(); + const graphqlOperation = createOneOperationFactory({ + objectMetadataSingularName: 'person', + gqlFields: PERSON_GQL_FIELDS, + data: { + id: personId, + }, + }); - // const response = await makeGraphqlAPIRequestWithApiKey(graphqlOperation); + const response = await makeGraphqlAPIRequestWithApiKey(graphqlOperation); - // expect(response.body.data).toBeDefined(); - // expect(response.body.data.createPerson).toBeDefined(); - // expect(response.body.data.createPerson.id).toBe(personId); - // }); - // }); + expect(response.body.data).toBeDefined(); + expect(response.body.data.createPerson).toBeDefined(); + expect(response.body.data.createPerson.id).toBe(personId); + }); + }); });