From f4ead899566f2100a9cd021bdfc18b1fc7cbce11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Malfait?= Date: Thu, 28 May 2026 20:46:21 +0200 Subject: [PATCH] refactor(twenty-orm): migrate 23 grandfathered entities to WorkspaceScopedRepository (#20987) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Follow-up to #20953. Migrates 23 of the 30 entities that were left in `WORKSPACE_SCOPED_EXEMPTIONS` last time, so the lint rule's workspaceId-enforcement default now covers most of the core/metadata schema. ### Migrated (23 entities, 88 files, 22 commits) | Family | Entities | |---|---| | Trivial caches | `NavigationMenuItem`, `Skill`, `DataSource`, `Webhook`, `CommandMenuItem`, `IndexMetadata` | | Views | `View`, `ViewField`, `ViewFieldGroup`, `ViewFilter`, `ViewFilterGroup`, `ViewGroup`, `ViewSort` | | Layouts | `PageLayout`, `PageLayoutTab`, `PageLayoutWidget` | | Roles & permissions | `Role`, `RoleTarget`, `PermissionFlag`, `ObjectPermission`, `FieldPermission`, `RowLevelPermissionPredicate`, `RowLevelPermissionPredicateGroup` | For each entity: swap `@InjectRepository(X)` → `@InjectWorkspaceScopedRepository(X)` (and the field type → `WorkspaceScopedRepository`); rewrite every call site to pass `workspaceId` as the first arg (stripped from `where`/criteria — the wrapper throws if you include it now); register `provideWorkspaceScopedRepository(X)` in every owning NestJS module; update affected spec providers to `getWorkspaceScopedRepositoryToken(X)`. ### Rule update - `ApplicationRegistrationVariableEntity` was misclassified — moved to `STRUCTURAL_EXEMPTIONS` (no `workspaceId` column; it's keyed on `applicationRegistrationId` at the instance level). - 22 of the 23 migrated entities removed from `WORKSPACE_SCOPED_EXEMPTIONS` entirely (zero remaining raw `@InjectRepository` sites). - `RoleTargetEntity` also removed; one call site in `user-workspace.service.ts` keeps a raw injection with an `eslint-disable` + reason because `softRemove(...)` is not on the wrapper API yet (the migration would require threading `workspaceId` through `deleteUserWorkspace`'s three callers). ### Still exempted (7 entities, follow-up PRs) | Entity | Why deferred | |---|---| | `ApplicationEntity` | ~50 sites with several cross-workspace lookups by id (auth, OAuth, file-storage, cleanup) | | `CalendarChannelEntity` / `MessageChannelEntity` | Use `.increment(...)` (not on wrapper) and `repository.manager.transaction(...)` — wrapper needs to grow `.increment` + the transaction sites need `withManager` or dual-inject | | `FieldMetadataEntity` / `ObjectMetadataEntity` | The metadata services `extends TypeOrmQueryService` and `super(rawRepo)` — requires dual-inject or reworking the inheritance | | `KeyValuePairEntity` | Allows `workspaceId: IsNull()` for instance-level config; wrapper rejects null | | `UpgradeMigrationEntity` | Same — instance-level + cross-workspace ledger | ## Test plan - [x] `npx nx typecheck twenty-server` — clean - [x] `npx nx lint twenty-server` — clean (0/0) - [x] All 10 affected unit specs pass (115 tests) — api-key, agent-role, permissions, workspace-roles-permissions-cache, view-filter-group, workflow-version-step-operations, two-factor-authentication (service + resolver), user-workspace, file - [ ] Server integration tests in CI --- .../prefer-workspace-scoped-repository.ts | 50 +++---- .../commands/database-command.module.ts | 5 +- .../core-modules/api-key/api-key.module.ts | 2 + .../commands/generate-api-key.command.ts | 9 +- .../__tests__/api-key.service.spec.ts | 4 +- .../api-key/services/api-key-role.service.ts | 35 +++-- .../application/application.module.ts | 1 + .../application/application.service.ts | 8 +- .../user-workspace/user-workspace.service.ts | 5 + .../ai-agent-execution.module.ts | 2 + .../services/agent-async-executor.service.ts | 9 +- .../ai-agent-role/agent-role.service.spec.ts | 52 +++---- .../ai/ai-agent-role/ai-agent-role.module.ts | 2 + .../ai/ai-agent-role/ai-agent-role.service.ts | 64 ++++---- .../flat-agent/flat-agent.module.ts | 2 + ...ce-flat-role-target-by-agent-id.service.ts | 16 +- .../flat-command-menu-item.module.ts | 7 +- ...lat-command-menu-item-map-cache.service.ts | 16 +- ...ny-or-all-flat-entity-maps-cache.module.ts | 18 +++ ...e-flat-field-metadata-map-cache.service.ts | 42 +++--- ...flat-field-permission-map-cache.service.ts | 16 +- .../workspace-flat-index-map-cache.service.ts | 11 +- .../flat-navigation-menu-item.module.ts | 8 +- ...-navigation-menu-item-map-cache.service.ts | 23 ++- ...-flat-object-metadata-map-cache.service.ts | 23 ++- ...lat-object-permission-map-cache.service.ts | 16 +- .../flat-page-layout-tab.module.ts | 8 +- ...-flat-page-layout-tab-map-cache.service.ts | 23 ++- .../flat-page-layout-widget.module.ts | 4 + ...at-page-layout-widget-map-cache.service.ts | 23 ++- .../flat-page-layout.module.ts | 7 +- ...pace-flat-page-layout-map-cache.service.ts | 16 +- .../flat-permission-flag.module.ts | 6 +- ...-flat-permission-flag-map-cache.service.ts | 9 +- ...-role-permission-flag-map-cache.service.ts | 16 +- ...pace-flat-role-target-map-cache.service.ts | 16 +- ...ssion-predicate-group-map-cache.service.ts | 23 ++- ...-permission-predicate-map-cache.service.ts | 23 ++- .../flat-skill/flat-skill.module.ts | 6 +- .../workspace-flat-skill-map-cache.service.ts | 9 +- ...flat-view-field-group-map-cache.service.ts | 23 ++- ...space-flat-view-field-map-cache.service.ts | 23 ++- ...lat-view-filter-group-map-cache.service.ts | 23 ++- ...pace-flat-view-filter-map-cache.service.ts | 23 ++- ...space-flat-view-group-map-cache.service.ts | 16 +- ...kspace-flat-view-sort-map-cache.service.ts | 16 +- .../flat-view/flat-view.module.ts | 12 +- .../workspace-flat-view-map-cache.service.ts | 51 +++---- .../flat-webhook/flat-webhook.module.ts | 6 +- ...orkspace-flat-webhook-map-cache.service.ts | 10 +- .../__tests__/permissions.service.spec.ts | 3 +- .../permissions/permissions.module.ts | 2 + .../permissions/permissions.service.ts | 18 ++- .../role-target/role-target.module.ts | 2 + ...orkspace-api-key-role-map-cache.service.ts | 12 +- ...e-user-workspace-role-map-cache.service.ts | 12 +- .../role-validation/role-validation.module.ts | 6 +- .../services/role-validation.service.ts | 12 +- .../metadata-modules/role/role.module.ts | 7 + .../metadata-modules/role/role.service.ts | 14 +- ...ce-roles-permissions-cache.service.spec.ts | 22 ++- .../workspace-flat-role-map-cache.service.ts | 44 +++--- ...rkspace-roles-permissions-cache.service.ts | 42 +++--- .../row-level-permission.module.ts | 2 + ...evel-permission-predicate-group.service.ts | 13 +- .../user-role/user-role.module.ts | 6 +- .../user-role/user-role.service.ts | 9 +- .../services/fields-widget-upsert.service.ts | 13 +- .../view-field-group.module.ts | 2 + .../tests/view-filter-group.service.spec.ts | 50 +++---- .../services/view-filter-group.service.ts | 43 +++--- .../view-filter-group.module.ts | 7 +- .../services/view-filter.service.ts | 18 +-- .../view-filter/view-filter.module.ts | 8 +- .../view-group/services/view-group.service.ts | 18 +-- .../view-group/view-group.module.ts | 7 +- .../services/view-entity-lookup.service.ts | 45 +++--- .../view-permissions.module.ts | 7 + .../view-sort/services/view-sort.service.ts | 18 +-- .../view-sort/view-sort.module.ts | 8 +- .../services/view-widget-upsert.service.ts | 26 ++-- .../view/services/view.service.ts | 11 +- .../metadata-modules/view/view.module.ts | 2 + .../webhook/webhook.module.ts | 2 + .../webhook/webhook.service.ts | 14 +- .../workspace-scoped-repository.spec.ts | 137 ++++++++++++++++++ .../workspace-scoped-repository.ts | 94 ++++++++++++ .../dev-seeder-permissions.service.ts | 9 +- .../dev-seeder/dev-seeder.module.ts | 3 + .../workspace-manager.module.ts | 6 +- .../workspace-manager.service.ts | 9 +- .../calendar-event-import-manager.module.ts | 2 + ...-event-import-exception-handler.service.ts | 22 +-- .../messaging-import-manager.module.ts | 2 + ...g-import-exception-handler.service.spec.ts | 6 +- ...saging-import-exception-handler.service.ts | 24 +-- ...-step-operations.workspace-service.spec.ts | 3 +- ...rsion-step-operations.workspace-service.ts | 18 ++- .../workflow-version-step.module.ts | 2 + 99 files changed, 1037 insertions(+), 663 deletions(-) diff --git a/packages/twenty-oxlint-rules/rules/prefer-workspace-scoped-repository.ts b/packages/twenty-oxlint-rules/rules/prefer-workspace-scoped-repository.ts index ed004bdd4e7..b293a02ab43 100644 --- a/packages/twenty-oxlint-rules/rules/prefer-workspace-scoped-repository.ts +++ b/packages/twenty-oxlint-rules/rules/prefer-workspace-scoped-repository.ts @@ -2,12 +2,18 @@ import { defineRule } from '@oxlint/plugins'; export const RULE_NAME = 'prefer-workspace-scoped-repository'; -// Entities that legitimately do not carry a workspaceId column. +// Entities that do not fit the scoped wrapper: workspace itself, pivots, +// nullable-workspaceId rows (instance-level config / migrations / tokens), +// and global tables with no workspaceId column at all. const STRUCTURAL_EXEMPTIONS = new Set([ 'WorkspaceEntity', 'UserWorkspaceEntity', 'AppTokenEntity', 'ApplicationRegistrationEntity', + 'ApplicationRegistrationVariableEntity', + // nullable workspaceId — both rows support instance-level and per-workspace use + 'KeyValuePairEntity', + 'UpgradeMigrationEntity', 'ApplicationVariableEntity', 'BillingMeterEntity', @@ -25,39 +31,25 @@ const STRUCTURAL_EXEMPTIONS = new Set([ 'WorkspaceSSOIdentityProviderEntity', ]); -// Workspace-scoped entities exempted from the wrapper at the call site. +// Workspace-scoped entities the wrapper could technically wrap, but where +// the dominant access patterns are cross-workspace (request routing, auth, +// metadata sync, file storage, transaction-bound channel updates) and the +// payoff doesn't justify dual-injecting every call site or growing the +// wrapper API. Treat as a "deliberately not migrated" list, not a backlog. const WORKSPACE_SCOPED_EXEMPTIONS = new Set([ + // Resolved by id alone at auth/request-routing time and inside file-storage + // transactions; very few of the ~50 call sites carry a workspaceId. 'ApplicationEntity', - 'ApplicationRegistrationVariableEntity', + // 20+ call sites across calendar/messaging modules; staged for a dedicated PR. 'CalendarChannelEntity', - 'CommandMenuItemEntity', - 'DataSourceEntity', - 'FieldMetadataEntity', - 'FieldPermissionEntity', - 'IndexMetadataEntity', - 'KeyValuePairEntity', 'MessageChannelEntity', - 'NavigationMenuItemEntity', + // The owning services `extends TypeOrmQueryService` and pass the raw + // repo to `super(...)`; the superclass type doesn't accept the wrapper. + 'FieldMetadataEntity', 'ObjectMetadataEntity', - 'ObjectPermissionEntity', - 'PageLayoutEntity', - 'PageLayoutTabEntity', - 'PageLayoutWidgetEntity', - 'PermissionFlagEntity', - 'RoleEntity', - 'RoleTargetEntity', - 'RowLevelPermissionPredicateEntity', - 'RowLevelPermissionPredicateGroupEntity', - 'SkillEntity', - 'UpgradeMigrationEntity', - 'ViewEntity', - 'ViewFieldEntity', - 'ViewFieldGroupEntity', - 'ViewFilterEntity', - 'ViewFilterGroupEntity', - 'ViewGroupEntity', - 'ViewSortEntity', - 'WebhookEntity', + // Only injection lives in a frozen historical upgrade-version-command + // directory that CI's mutation-guard refuses to let us edit. + 'DataSourceEntity', ]); // Everything else must use @InjectWorkspaceScopedRepository. diff --git a/packages/twenty-server/src/database/commands/database-command.module.ts b/packages/twenty-server/src/database/commands/database-command.module.ts index 21780e6745d..25b8649fcbc 100644 --- a/packages/twenty-server/src/database/commands/database-command.module.ts +++ b/packages/twenty-server/src/database/commands/database-command.module.ts @@ -36,6 +36,8 @@ import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.ent import { WorkspaceModule } from 'src/engine/core-modules/workspace/workspace.module'; import { FieldMetadataModule } from 'src/engine/metadata-modules/field-metadata/field-metadata.module'; import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module'; +import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; +import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/provide-workspace-scoped-repository'; import { TrashCleanupModule } from 'src/engine/trash-cleanup/trash-cleanup.module'; import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/workspace-cache-storage.module'; import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module'; @@ -52,7 +54,7 @@ import { AutomatedTriggerModule } from 'src/modules/workflow/workflow-trigger/au @Module({ imports: [ UpgradeVersionCommandModule, - TypeOrmModule.forFeature([WorkspaceEntity]), + TypeOrmModule.forFeature([WorkspaceEntity, RoleEntity]), WorkspaceExportModule, // Cron command dependencies MessagingImportManagerModule, @@ -102,6 +104,7 @@ import { AutomatedTriggerModule } from 'src/modules/workflow/workflow-trigger/au UpgradeStatusCommand, RebuildApplicationDefaultDepsCommand, InstallPreInstalledAppsCommand, + provideWorkspaceScopedRepository(RoleEntity), ], }) export class DatabaseCommandModule {} diff --git a/packages/twenty-server/src/engine/core-modules/api-key/api-key.module.ts b/packages/twenty-server/src/engine/core-modules/api-key/api-key.module.ts index e4e245ebec8..73f55feb8c7 100644 --- a/packages/twenty-server/src/engine/core-modules/api-key/api-key.module.ts +++ b/packages/twenty-server/src/engine/core-modules/api-key/api-key.module.ts @@ -44,6 +44,8 @@ import { ApiKeyController } from './controllers/api-key.controller'; WorkspaceApiKeyMapCacheService, GenerateApiKeyCommand, provideWorkspaceScopedRepository(ApiKeyEntity), + provideWorkspaceScopedRepository(RoleEntity), + provideWorkspaceScopedRepository(RoleTargetEntity), ], controllers: [ApiKeyController], exports: [ diff --git a/packages/twenty-server/src/engine/core-modules/api-key/commands/generate-api-key.command.ts b/packages/twenty-server/src/engine/core-modules/api-key/commands/generate-api-key.command.ts index 29d08c88620..f52e2784886 100644 --- a/packages/twenty-server/src/engine/core-modules/api-key/commands/generate-api-key.command.ts +++ b/packages/twenty-server/src/engine/core-modules/api-key/commands/generate-api-key.command.ts @@ -13,6 +13,8 @@ import { ApiKeyService } from 'src/engine/core-modules/api-key/services/api-key. import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service'; import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { STANDARD_ROLE } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-role.constant'; type GenerateApiKeyCommandOptions = { @@ -33,8 +35,8 @@ export class GenerateApiKeyCommand extends CommandRunner { constructor( @InjectRepository(WorkspaceEntity) private readonly workspaceRepository: Repository, - @InjectRepository(RoleEntity) - private readonly roleRepository: Repository, + @InjectWorkspaceScopedRepository(RoleEntity) + private readonly roleRepository: WorkspaceScopedRepository, private readonly apiKeyService: ApiKeyService, private readonly twentyConfigService: TwentyConfigService, ) { @@ -104,9 +106,8 @@ export class GenerateApiKeyCommand extends CommandRunner { return; } - const adminRole = await this.roleRepository.findOne({ + const adminRole = await this.roleRepository.findOne(workspace.id, { where: { - workspaceId: workspace.id, universalIdentifier: STANDARD_ROLE.admin.universalIdentifier, }, }); diff --git a/packages/twenty-server/src/engine/core-modules/api-key/services/__tests__/api-key.service.spec.ts b/packages/twenty-server/src/engine/core-modules/api-key/services/__tests__/api-key.service.spec.ts index e4297dec57b..5329dce6bb0 100644 --- a/packages/twenty-server/src/engine/core-modules/api-key/services/__tests__/api-key.service.spec.ts +++ b/packages/twenty-server/src/engine/core-modules/api-key/services/__tests__/api-key.service.spec.ts @@ -1,5 +1,5 @@ import { Test, type TestingModule } from '@nestjs/testing'; -import { getDataSourceToken, getRepositoryToken } from '@nestjs/typeorm'; +import { getDataSourceToken } from '@nestjs/typeorm'; import { IsNull } from 'typeorm'; @@ -101,7 +101,7 @@ describe('ApiKeyService', () => { useValue: mockRoleTargetService, }, { - provide: getRepositoryToken(RoleTargetEntity), + provide: getWorkspaceScopedRepositoryToken(RoleTargetEntity), useValue: mockroleTargetRepository, }, { diff --git a/packages/twenty-server/src/engine/core-modules/api-key/services/api-key-role.service.ts b/packages/twenty-server/src/engine/core-modules/api-key/services/api-key-role.service.ts index 52f9506b691..314a7bddae2 100644 --- a/packages/twenty-server/src/engine/core-modules/api-key/services/api-key-role.service.ts +++ b/packages/twenty-server/src/engine/core-modules/api-key/services/api-key-role.service.ts @@ -1,8 +1,7 @@ import { Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; import { isDefined } from 'twenty-shared/utils'; -import { In, IsNull, Not, Repository } from 'typeorm'; +import { In, IsNull, Not } from 'typeorm'; import { ApiKeyEntity } from 'src/engine/core-modules/api-key/api-key.entity'; import { @@ -23,10 +22,10 @@ import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/works @Injectable() export class ApiKeyRoleService { constructor( - @InjectRepository(RoleTargetEntity) - private readonly roleTargetRepository: Repository, - @InjectRepository(RoleEntity) - private readonly roleRepository: Repository, + @InjectWorkspaceScopedRepository(RoleTargetEntity) + private readonly roleTargetRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(RoleEntity) + private readonly roleRepository: WorkspaceScopedRepository, @InjectWorkspaceScopedRepository(ApiKeyEntity) private readonly apiKeyRepository: WorkspaceScopedRepository, @@ -141,8 +140,8 @@ export class ApiKeyRoleService { ); } - const role = await this.roleRepository.findOne({ - where: { id: roleId, workspaceId }, + const role = await this.roleRepository.findOne(workspaceId, { + where: { id: roleId }, }); if (!role) { @@ -159,13 +158,15 @@ export class ApiKeyRoleService { ); } - const existingRoleTarget = await this.roleTargetRepository.findOne({ - where: { - apiKeyId, - roleId, - workspaceId, + const existingRoleTarget = await this.roleTargetRepository.findOne( + workspaceId, + { + where: { + apiKeyId, + roleId, + }, }, - }); + ); return { roleToAssignIsSameAsCurrentRole: Boolean(existingRoleTarget), @@ -183,10 +184,9 @@ export class ApiKeyRoleService { return new Map(); } - const roleTargets = await this.roleTargetRepository.find({ + const roleTargets = await this.roleTargetRepository.find(workspaceId, { where: { apiKeyId: In(apiKeyIds), - workspaceId, }, relations: ['role'], }); @@ -209,10 +209,9 @@ export class ApiKeyRoleService { roleId: string, workspaceId: string, ): Promise { - const roleTargets = await this.roleTargetRepository.find({ + const roleTargets = await this.roleTargetRepository.find(workspaceId, { where: { roleId, - workspaceId, apiKeyId: Not(IsNull()), }, }); diff --git a/packages/twenty-server/src/engine/core-modules/application/application.module.ts b/packages/twenty-server/src/engine/core-modules/application/application.module.ts index b24e4814bd3..3be9c01fd10 100644 --- a/packages/twenty-server/src/engine/core-modules/application/application.module.ts +++ b/packages/twenty-server/src/engine/core-modules/application/application.module.ts @@ -39,6 +39,7 @@ import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache ApplicationService, WorkspaceFlatApplicationMapCacheService, provideWorkspaceScopedRepository(AgentEntity), + provideWorkspaceScopedRepository(CommandMenuItemEntity), ], }) export class ApplicationModule {} diff --git a/packages/twenty-server/src/engine/core-modules/application/application.service.ts b/packages/twenty-server/src/engine/core-modules/application/application.service.ts index e9ccdf5db54..f8d98a00011 100644 --- a/packages/twenty-server/src/engine/core-modules/application/application.service.ts +++ b/packages/twenty-server/src/engine/core-modules/application/application.service.ts @@ -43,8 +43,8 @@ export class ApplicationService { private readonly agentRepository: WorkspaceScopedRepository, @InjectRepository(FrontComponentEntity) private readonly frontComponentRepository: Repository, - @InjectRepository(CommandMenuItemEntity) - private readonly commandMenuItemRepository: Repository, + @InjectWorkspaceScopedRepository(CommandMenuItemEntity) + private readonly commandMenuItemRepository: WorkspaceScopedRepository, @InjectRepository(ObjectMetadataEntity) private readonly objectMetadataRepository: Repository, @InjectRepository(ApplicationVariableEntity) @@ -206,8 +206,8 @@ export class ApplicationService { this.frontComponentRepository.find({ where: { applicationId: application.id, workspaceId }, }), - this.commandMenuItemRepository.find({ - where: { applicationId: application.id, workspaceId }, + this.commandMenuItemRepository.find(workspaceId, { + where: { applicationId: application.id }, }), this.objectMetadataRepository.find({ where: { applicationId: application.id, workspaceId }, diff --git a/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.service.ts b/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.service.ts index ed052584bed..72ba4e047e2 100644 --- a/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.service.ts +++ b/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.service.ts @@ -51,6 +51,8 @@ export class UserWorkspaceService extends TypeOrmQueryService, @InjectRepository(UserEntity) private readonly userRepository: Repository, + // softRemove is not supported by WorkspaceScopedRepository. + // eslint-disable-next-line twenty/prefer-workspace-scoped-repository @InjectRepository(RoleTargetEntity) private readonly roleTargetRepository: Repository, private readonly roleValidationService: RoleValidationService, @@ -311,6 +313,9 @@ export class UserWorkspaceService extends TypeOrmQueryService, + @InjectWorkspaceScopedRepository(RoleTargetEntity) + private readonly roleTargetRepository: WorkspaceScopedRepository, @InjectRepository(WorkspaceEntity) private readonly workspaceRepository: Repository, ) {} @@ -104,10 +106,9 @@ export class AgentAsyncExecutorService { workspaceId: string, rolePermissionConfig?: RolePermissionConfig, ): Promise { - const roleTarget = await this.roleTargetRepository.findOne({ + const roleTarget = await this.roleTargetRepository.findOne(workspaceId, { where: { agentId, - workspaceId, }, select: ['roleId'], }); diff --git a/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-role/agent-role.service.spec.ts b/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-role/agent-role.service.spec.ts index 94d37e9369c..9c6bf6725ad 100644 --- a/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-role/agent-role.service.spec.ts +++ b/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-role/agent-role.service.spec.ts @@ -1,7 +1,4 @@ import { Test, type TestingModule } from '@nestjs/testing'; -import { getRepositoryToken } from '@nestjs/typeorm'; - -import { type Repository } from 'typeorm'; import { AiException, @@ -20,8 +17,8 @@ import { AiAgentRoleService } from './ai-agent-role.service'; describe('AiAgentRoleService', () => { let service: AiAgentRoleService; let agentRepository: WorkspaceScopedRepository; - let roleRepository: Repository; - let roleTargetRepository: Repository; + let roleRepository: WorkspaceScopedRepository; + let roleTargetRepository: WorkspaceScopedRepository; let roleTargetService: RoleTargetService; const testWorkspaceId = 'test-workspace-id'; @@ -42,19 +39,20 @@ describe('AiAgentRoleService', () => { }, }, { - provide: getRepositoryToken(RoleEntity), + provide: getWorkspaceScopedRepositoryToken(RoleEntity), useValue: { findOne: jest.fn(), save: jest.fn(), }, }, { - provide: getRepositoryToken(RoleTargetEntity), + provide: getWorkspaceScopedRepositoryToken(RoleTargetEntity), useValue: { findOne: jest.fn(), save: jest.fn(), delete: jest.fn(), find: jest.fn(), + count: jest.fn(), }, }, { @@ -71,12 +69,12 @@ describe('AiAgentRoleService', () => { agentRepository = module.get>( getWorkspaceScopedRepositoryToken(AgentEntity), ); - roleRepository = module.get>( - getRepositoryToken(RoleEntity), - ); - roleTargetRepository = module.get>( - getRepositoryToken(RoleTargetEntity), + roleRepository = module.get>( + getWorkspaceScopedRepositoryToken(RoleEntity), ); + roleTargetRepository = module.get< + WorkspaceScopedRepository + >(getWorkspaceScopedRepositoryToken(RoleTargetEntity)); roleTargetService = module.get(RoleTargetService); // Setup test data @@ -153,16 +151,18 @@ describe('AiAgentRoleService', () => { expect(agentRepository.findOne).toHaveBeenCalledWith(testWorkspaceId, { where: { id: testAgent.id }, }); - expect(roleRepository.findOne).toHaveBeenCalledWith({ - where: { id: testRole.id, workspaceId: testWorkspaceId }, + expect(roleRepository.findOne).toHaveBeenCalledWith(testWorkspaceId, { + where: { id: testRole.id }, }); - expect(roleTargetRepository.findOne).toHaveBeenCalledWith({ - where: { - agentId: testAgent.id, - roleId: testRole.id, - workspaceId: testWorkspaceId, + expect(roleTargetRepository.findOne).toHaveBeenCalledWith( + testWorkspaceId, + { + where: { + agentId: testAgent.id, + roleId: testRole.id, + }, }, - }); + ); expect(roleTargetService.create).toHaveBeenCalledWith({ createRoleTargetInput: { roleId: testRole.id, @@ -335,12 +335,14 @@ describe('AiAgentRoleService', () => { }); // Assert - expect(roleTargetRepository.findOne).toHaveBeenCalledWith({ - where: { - agentId: testAgent.id, - workspaceId: testWorkspaceId, + expect(roleTargetRepository.findOne).toHaveBeenCalledWith( + testWorkspaceId, + { + where: { + agentId: testAgent.id, + }, }, - }); + ); expect(roleTargetService.delete).toHaveBeenCalledWith({ id: existingRoleTarget.id, workspaceId: testWorkspaceId, diff --git a/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-role/ai-agent-role.module.ts b/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-role/ai-agent-role.module.ts index c426287f1d2..878e0ba0cab 100644 --- a/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-role/ai-agent-role.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-role/ai-agent-role.module.ts @@ -16,6 +16,8 @@ import { AiAgentRoleService } from './ai-agent-role.service'; providers: [ AiAgentRoleService, provideWorkspaceScopedRepository(AgentEntity), + provideWorkspaceScopedRepository(RoleEntity), + provideWorkspaceScopedRepository(RoleTargetEntity), ], exports: [AiAgentRoleService], }) diff --git a/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-role/ai-agent-role.service.ts b/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-role/ai-agent-role.service.ts index 9388475e604..7315150d285 100644 --- a/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-role/ai-agent-role.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-role/ai-agent-role.service.ts @@ -1,8 +1,7 @@ import { Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; import { isDefined } from 'twenty-shared/utils'; -import { In, IsNull, Not, Repository } from 'typeorm'; +import { In, IsNull, Not } from 'typeorm'; import { AiException, @@ -19,10 +18,10 @@ export class AiAgentRoleService { constructor( @InjectWorkspaceScopedRepository(AgentEntity) private readonly agentRepository: WorkspaceScopedRepository, - @InjectRepository(RoleEntity) - private readonly roleRepository: Repository, - @InjectRepository(RoleTargetEntity) - private readonly roleTargetRepository: Repository, + @InjectWorkspaceScopedRepository(RoleEntity) + private readonly roleRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(RoleTargetEntity) + private readonly roleTargetRepository: WorkspaceScopedRepository, private readonly roleTargetService: RoleTargetService, ) {} @@ -62,12 +61,14 @@ export class AiAgentRoleService { workspaceId: string; agentId: string; }): Promise { - const existingRoleTarget = await this.roleTargetRepository.findOne({ - where: { - agentId, - workspaceId, + const existingRoleTarget = await this.roleTargetRepository.findOne( + workspaceId, + { + where: { + agentId, + }, }, - }); + ); if (!isDefined(existingRoleTarget)) { throw new AiException( @@ -86,10 +87,9 @@ export class AiAgentRoleService { roleId: string, workspaceId: string, ): Promise { - const roleTargets = await this.roleTargetRepository.find({ + const roleTargets = await this.roleTargetRepository.find(workspaceId, { where: { roleId, - workspaceId, agentId: Not(IsNull()), }, }); @@ -129,8 +129,8 @@ export class AiAgentRoleService { ); } - const role = await this.roleRepository.findOne({ - where: { id: roleId, workspaceId }, + const role = await this.roleRepository.findOne(workspaceId, { + where: { id: roleId }, }); if (!role) { @@ -147,13 +147,15 @@ export class AiAgentRoleService { ); } - const existingRoleTarget = await this.roleTargetRepository.findOne({ - where: { - agentId, - roleId, - workspaceId, + const existingRoleTarget = await this.roleTargetRepository.findOne( + workspaceId, + { + where: { + agentId, + roleId, + }, }, - }); + ); return { roleToAssignIsSameAsCurrentRole: Boolean(existingRoleTarget), @@ -169,8 +171,8 @@ export class AiAgentRoleService { roleTargetId: string; workspaceId: string; }): Promise { - const role = await this.roleRepository.findOne({ - where: { id: roleId, workspaceId }, + const role = await this.roleRepository.findOne(workspaceId, { + where: { id: roleId }, }); if ( @@ -182,16 +184,18 @@ export class AiAgentRoleService { return; } - const remainingAssignments = await this.roleTargetRepository.count({ - where: { - roleId, - workspaceId, - id: Not(roleTargetId), + const remainingAssignments = await this.roleTargetRepository.count( + workspaceId, + { + where: { + roleId, + id: Not(roleTargetId), + }, }, - }); + ); if (remainingAssignments === 0) { - await this.roleRepository.delete({ id: roleId, workspaceId }); + await this.roleRepository.delete(workspaceId, { id: roleId }); } } } diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-agent/flat-agent.module.ts b/packages/twenty-server/src/engine/metadata-modules/flat-agent/flat-agent.module.ts index 4f60eeb81d4..d8b1f8ebddb 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-agent/flat-agent.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-agent/flat-agent.module.ts @@ -23,6 +23,8 @@ import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspac WorkspaceFlatAgentMapCacheService, WorkspaceFlatRoleTargetByAgentIdService, provideWorkspaceScopedRepository(AgentEntity), + provideWorkspaceScopedRepository(RoleEntity), + provideWorkspaceScopedRepository(RoleTargetEntity), ], exports: [ WorkspaceFlatAgentMapCacheService, diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-agent/services/workspace-flat-role-target-by-agent-id.service.ts b/packages/twenty-server/src/engine/metadata-modules/flat-agent/services/workspace-flat-role-target-by-agent-id.service.ts index 530aa23f2ae..20b5d2f19c1 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-agent/services/workspace-flat-role-target-by-agent-id.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-agent/services/workspace-flat-role-target-by-agent-id.service.ts @@ -11,6 +11,8 @@ import { FlatRoleTargetByAgentIdMaps } from 'src/engine/metadata-modules/flat-ag import { fromRoleTargetEntityToFlatRoleTarget } from 'src/engine/metadata-modules/flat-role-target/utils/from-role-target-entity-to-flat-role-target.util'; import { RoleTargetEntity } from 'src/engine/metadata-modules/role-target/role-target.entity'; import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator'; import { createIdToUniversalIdentifierMap } from 'src/engine/workspace-cache/utils/create-id-to-universal-identifier-map.util'; @@ -18,12 +20,12 @@ import { createIdToUniversalIdentifierMap } from 'src/engine/workspace-cache/uti @WorkspaceCache('flatRoleTargetByAgentIdMaps') export class WorkspaceFlatRoleTargetByAgentIdService extends WorkspaceCacheProvider { constructor( - @InjectRepository(RoleTargetEntity) - private readonly roleTargetRepository: Repository, + @InjectWorkspaceScopedRepository(RoleTargetEntity) + private readonly roleTargetRepository: WorkspaceScopedRepository, @InjectRepository(ApplicationEntity) private readonly applicationRepository: Repository, - @InjectRepository(RoleEntity) - private readonly roleRepository: Repository, + @InjectWorkspaceScopedRepository(RoleEntity) + private readonly roleRepository: WorkspaceScopedRepository, ) { super(); } @@ -32,9 +34,8 @@ export class WorkspaceFlatRoleTargetByAgentIdService extends WorkspaceCacheProvi workspaceId: string, ): Promise { const [roleTargetEntities, applications, roles] = await Promise.all([ - this.roleTargetRepository.find({ + this.roleTargetRepository.find(workspaceId, { where: { - workspaceId, agentId: Not(IsNull()), }, withDeleted: true, @@ -44,8 +45,7 @@ export class WorkspaceFlatRoleTargetByAgentIdService extends WorkspaceCacheProvi select: ['id', 'universalIdentifier'], withDeleted: true, }), - this.roleRepository.find({ - where: { workspaceId }, + this.roleRepository.find(workspaceId, { select: ['id', 'universalIdentifier'], withDeleted: true, }), diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-command-menu-item/flat-command-menu-item.module.ts b/packages/twenty-server/src/engine/metadata-modules/flat-command-menu-item/flat-command-menu-item.module.ts index 7af808d7f74..83948b77715 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-command-menu-item/flat-command-menu-item.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-command-menu-item/flat-command-menu-item.module.ts @@ -8,6 +8,7 @@ import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata import { FrontComponentEntity } from 'src/engine/metadata-modules/front-component/entities/front-component.entity'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { PageLayoutEntity } from 'src/engine/metadata-modules/page-layout/entities/page-layout.entity'; +import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/provide-workspace-scoped-repository'; @Module({ imports: [ @@ -20,7 +21,11 @@ import { PageLayoutEntity } from 'src/engine/metadata-modules/page-layout/entiti ]), WorkspaceManyOrAllFlatEntityMapsCacheModule, ], - providers: [WorkspaceFlatCommandMenuItemMapCacheService], + providers: [ + WorkspaceFlatCommandMenuItemMapCacheService, + provideWorkspaceScopedRepository(CommandMenuItemEntity), + provideWorkspaceScopedRepository(PageLayoutEntity), + ], exports: [WorkspaceFlatCommandMenuItemMapCacheService], }) export class FlatCommandMenuItemModule {} diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-command-menu-item/services/workspace-flat-command-menu-item-map-cache.service.ts b/packages/twenty-server/src/engine/metadata-modules/flat-command-menu-item/services/workspace-flat-command-menu-item-map-cache.service.ts index 30250dfe7d0..edfb2ead26e 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-command-menu-item/services/workspace-flat-command-menu-item-map-cache.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-command-menu-item/services/workspace-flat-command-menu-item-map-cache.service.ts @@ -13,6 +13,8 @@ import { createEmptyFlatEntityMaps } from 'src/engine/metadata-modules/flat-enti import { FrontComponentEntity } from 'src/engine/metadata-modules/front-component/entities/front-component.entity'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { PageLayoutEntity } from 'src/engine/metadata-modules/page-layout/entities/page-layout.entity'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator'; import { createIdToUniversalIdentifierMap } from 'src/engine/workspace-cache/utils/create-id-to-universal-identifier-map.util'; import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/workspace-manager/workspace-migration/utils/add-flat-entity-to-flat-entity-maps-through-mutation-or-throw.util'; @@ -21,16 +23,16 @@ import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/ @WorkspaceCache('flatCommandMenuItemMaps') export class WorkspaceFlatCommandMenuItemMapCacheService extends WorkspaceCacheProvider { constructor( - @InjectRepository(CommandMenuItemEntity) - private readonly commandMenuItemRepository: Repository, + @InjectWorkspaceScopedRepository(CommandMenuItemEntity) + private readonly commandMenuItemRepository: WorkspaceScopedRepository, @InjectRepository(ApplicationEntity) private readonly applicationRepository: Repository, @InjectRepository(ObjectMetadataEntity) private readonly objectMetadataRepository: Repository, @InjectRepository(FrontComponentEntity) private readonly frontComponentRepository: Repository, - @InjectRepository(PageLayoutEntity) - private readonly pageLayoutRepository: Repository, + @InjectWorkspaceScopedRepository(PageLayoutEntity) + private readonly pageLayoutRepository: WorkspaceScopedRepository, ) { super(); } @@ -43,8 +45,7 @@ export class WorkspaceFlatCommandMenuItemMapCacheService extends WorkspaceCacheP frontComponents, pageLayouts, ] = await Promise.all([ - this.commandMenuItemRepository.find({ - where: { workspaceId }, + this.commandMenuItemRepository.find(workspaceId, { withDeleted: true, }), this.applicationRepository.find({ @@ -62,8 +63,7 @@ export class WorkspaceFlatCommandMenuItemMapCacheService extends WorkspaceCacheP select: ['id', 'universalIdentifier'], withDeleted: true, }), - this.pageLayoutRepository.find({ - where: { workspaceId }, + this.pageLayoutRepository.find(workspaceId, { select: ['id', 'universalIdentifier'], withDeleted: true, }), diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module.ts b/packages/twenty-server/src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module.ts index 312c141009e..8147bb3045e 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module.ts @@ -44,6 +44,7 @@ import { ViewFilterEntity } from 'src/engine/metadata-modules/view-filter/entiti import { ViewGroupEntity } from 'src/engine/metadata-modules/view-group/entities/view-group.entity'; import { ViewSortEntity } from 'src/engine/metadata-modules/view-sort/entities/view-sort.entity'; import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity'; +import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/provide-workspace-scoped-repository'; import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module'; @Module({ @@ -96,6 +97,23 @@ import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache WorkspaceFlatPageLayoutWidgetMapCacheService, WorkspaceFlatRowLevelPermissionPredicateMapCacheService, WorkspaceFlatRowLevelPermissionPredicateGroupMapCacheService, + provideWorkspaceScopedRepository(PermissionFlagEntity), + provideWorkspaceScopedRepository(IndexMetadataEntity), + provideWorkspaceScopedRepository(ViewEntity), + provideWorkspaceScopedRepository(ViewFieldEntity), + provideWorkspaceScopedRepository(ViewFieldGroupEntity), + provideWorkspaceScopedRepository(ViewFilterEntity), + provideWorkspaceScopedRepository(ViewFilterGroupEntity), + provideWorkspaceScopedRepository(ViewGroupEntity), + provideWorkspaceScopedRepository(ViewSortEntity), + provideWorkspaceScopedRepository(PageLayoutEntity), + provideWorkspaceScopedRepository(PageLayoutTabEntity), + provideWorkspaceScopedRepository(PageLayoutWidgetEntity), + provideWorkspaceScopedRepository(ObjectPermissionEntity), + provideWorkspaceScopedRepository(FieldPermissionEntity), + provideWorkspaceScopedRepository(RoleEntity), + provideWorkspaceScopedRepository(RowLevelPermissionPredicateEntity), + provideWorkspaceScopedRepository(RowLevelPermissionPredicateGroupEntity), ], exports: [ WorkspaceManyOrAllFlatEntityMapsCacheService, diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/services/workspace-flat-field-metadata-map-cache.service.ts b/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/services/workspace-flat-field-metadata-map-cache.service.ts index c6100837348..dadff176d86 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/services/workspace-flat-field-metadata-map-cache.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/services/workspace-flat-field-metadata-map-cache.service.ts @@ -18,6 +18,8 @@ import { ViewFieldEntity } from 'src/engine/metadata-modules/view-field/entities import { ViewFilterEntity } from 'src/engine/metadata-modules/view-filter/entities/view-filter.entity'; import { ViewGroupEntity } from 'src/engine/metadata-modules/view-group/entities/view-group.entity'; import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator'; import { createIdToUniversalIdentifierMap } from 'src/engine/workspace-cache/utils/create-id-to-universal-identifier-map.util'; import { regroupEntitiesByRelatedEntityId } from 'src/engine/workspace-cache/utils/regroup-entities-by-related-entity-id'; @@ -32,22 +34,22 @@ export class WorkspaceFlatFieldMetadataMapCacheService extends WorkspaceCachePro constructor( @InjectRepository(FieldMetadataEntity) private readonly fieldMetadataRepository: Repository, - @InjectRepository(IndexMetadataEntity) - private readonly indexMetadataRepository: Repository, + @InjectWorkspaceScopedRepository(IndexMetadataEntity) + private readonly indexMetadataRepository: WorkspaceScopedRepository, @InjectRepository(ObjectMetadataEntity) private readonly objectMetadataRepository: Repository, @InjectRepository(ApplicationEntity) private readonly applicationRepository: Repository, - @InjectRepository(ViewFieldEntity) - private readonly viewFieldRepository: Repository, - @InjectRepository(ViewFilterEntity) - private readonly viewFilterRepository: Repository, - @InjectRepository(ViewGroupEntity) - private readonly viewGroupRepository: Repository, - @InjectRepository(ViewSortEntity) - private readonly viewSortRepository: Repository, - @InjectRepository(ViewEntity) - private readonly viewRepository: Repository, + @InjectWorkspaceScopedRepository(ViewFieldEntity) + private readonly viewFieldRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(ViewFilterEntity) + private readonly viewFilterRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(ViewGroupEntity) + private readonly viewGroupRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(ViewSortEntity) + private readonly viewSortRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(ViewEntity) + private readonly viewRepository: WorkspaceScopedRepository, ) { super(); } @@ -69,8 +71,8 @@ export class WorkspaceFlatFieldMetadataMapCacheService extends WorkspaceCachePro where: { workspaceId }, withDeleted: true, }), - this.indexMetadataRepository.find({ - where: { workspaceId, isUnique: true }, + this.indexMetadataRepository.find(workspaceId, { + where: { isUnique: true }, relations: ['indexFieldMetadatas'], withDeleted: true, }), @@ -84,23 +86,19 @@ export class WorkspaceFlatFieldMetadataMapCacheService extends WorkspaceCachePro select: ['id', 'universalIdentifier'], withDeleted: true, }), - this.viewFieldRepository.find({ - where: { workspaceId }, + this.viewFieldRepository.find(workspaceId, { select: ['id', 'universalIdentifier', 'fieldMetadataId'], withDeleted: true, }), - this.viewFilterRepository.find({ - where: { workspaceId }, + this.viewFilterRepository.find(workspaceId, { select: ['id', 'universalIdentifier', 'fieldMetadataId'], withDeleted: true, }), - this.viewSortRepository.find({ - where: { workspaceId }, + this.viewSortRepository.find(workspaceId, { select: ['id', 'universalIdentifier', 'fieldMetadataId'], withDeleted: true, }), - this.viewRepository.find({ - where: { workspaceId }, + this.viewRepository.find(workspaceId, { select: [ 'id', 'universalIdentifier', diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-field-permission/services/workspace-flat-field-permission-map-cache.service.ts b/packages/twenty-server/src/engine/metadata-modules/flat-field-permission/services/workspace-flat-field-permission-map-cache.service.ts index 710455a8184..b693dd7de80 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-field-permission/services/workspace-flat-field-permission-map-cache.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-field-permission/services/workspace-flat-field-permission-map-cache.service.ts @@ -11,6 +11,8 @@ import { fromFieldPermissionEntityToFlatFieldPermission } from 'src/engine/metad import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { FieldPermissionEntity } from 'src/engine/metadata-modules/object-permission/field-permission/field-permission.entity'; import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator'; import { WorkspaceCacheProvider } from 'src/engine/workspace-cache/interfaces/workspace-cache-provider.service'; import { createIdToUniversalIdentifierMap } from 'src/engine/workspace-cache/utils/create-id-to-universal-identifier-map.util'; @@ -20,12 +22,12 @@ import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/ @WorkspaceCache('flatFieldPermissionMaps') export class WorkspaceFlatFieldPermissionMapCacheService extends WorkspaceCacheProvider { constructor( - @InjectRepository(FieldPermissionEntity) - private readonly fieldPermissionRepository: Repository, + @InjectWorkspaceScopedRepository(FieldPermissionEntity) + private readonly fieldPermissionRepository: WorkspaceScopedRepository, @InjectRepository(ApplicationEntity) private readonly applicationRepository: Repository, - @InjectRepository(RoleEntity) - private readonly roleRepository: Repository, + @InjectWorkspaceScopedRepository(RoleEntity) + private readonly roleRepository: WorkspaceScopedRepository, @InjectRepository(ObjectMetadataEntity) private readonly objectMetadataRepository: Repository, @InjectRepository(FieldMetadataEntity) @@ -42,8 +44,7 @@ export class WorkspaceFlatFieldPermissionMapCacheService extends WorkspaceCacheP objectMetadatas, fieldMetadatas, ] = await Promise.all([ - this.fieldPermissionRepository.find({ - where: { workspaceId }, + this.fieldPermissionRepository.find(workspaceId, { withDeleted: true, }), this.applicationRepository.find({ @@ -51,8 +52,7 @@ export class WorkspaceFlatFieldPermissionMapCacheService extends WorkspaceCacheP select: ['id', 'universalIdentifier'], withDeleted: true, }), - this.roleRepository.find({ - where: { workspaceId }, + this.roleRepository.find(workspaceId, { select: ['id', 'universalIdentifier'], withDeleted: true, }), diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-index-metadata/services/workspace-flat-index-map-cache.service.ts b/packages/twenty-server/src/engine/metadata-modules/flat-index-metadata/services/workspace-flat-index-map-cache.service.ts index b4f8a73e54f..f23d4983fd8 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-index-metadata/services/workspace-flat-index-map-cache.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-index-metadata/services/workspace-flat-index-map-cache.service.ts @@ -13,6 +13,8 @@ import { FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-metada import { fromIndexMetadataEntityToFlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-metadata/utils/from-index-metadata-entity-to-flat-index-metadata.util'; import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator'; import { createIdToUniversalIdentifierMap } from 'src/engine/workspace-cache/utils/create-id-to-universal-identifier-map.util'; import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/workspace-manager/workspace-migration/utils/add-flat-entity-to-flat-entity-maps-through-mutation-or-throw.util'; @@ -23,8 +25,8 @@ export class WorkspaceFlatIndexMapCacheService extends WorkspaceCacheProvider< FlatEntityMaps > { constructor( - @InjectRepository(IndexMetadataEntity) - private readonly indexMetadataRepository: Repository, + @InjectWorkspaceScopedRepository(IndexMetadataEntity) + private readonly indexMetadataRepository: WorkspaceScopedRepository, @InjectRepository(ApplicationEntity) private readonly applicationRepository: Repository, @InjectRepository(ObjectMetadataEntity) @@ -40,10 +42,7 @@ export class WorkspaceFlatIndexMapCacheService extends WorkspaceCacheProvider< ): Promise> { const [indexes, applications, objectMetadatas, fieldMetadatas] = await Promise.all([ - this.indexMetadataRepository.find({ - where: { - workspaceId, - }, + this.indexMetadataRepository.find(workspaceId, { withDeleted: true, relationLoadStrategy: 'join', relations: ['indexFieldMetadatas'], diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-navigation-menu-item/flat-navigation-menu-item.module.ts b/packages/twenty-server/src/engine/metadata-modules/flat-navigation-menu-item/flat-navigation-menu-item.module.ts index 7048d569019..a0cb1fbd5e8 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-navigation-menu-item/flat-navigation-menu-item.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-navigation-menu-item/flat-navigation-menu-item.module.ts @@ -8,6 +8,7 @@ import { NavigationMenuItemEntity } from 'src/engine/metadata-modules/navigation import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { PageLayoutEntity } from 'src/engine/metadata-modules/page-layout/entities/page-layout.entity'; import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity'; +import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/provide-workspace-scoped-repository'; @Module({ imports: [ @@ -20,7 +21,12 @@ import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entit ]), WorkspaceManyOrAllFlatEntityMapsCacheModule, ], - providers: [WorkspaceFlatNavigationMenuItemMapCacheService], + providers: [ + WorkspaceFlatNavigationMenuItemMapCacheService, + provideWorkspaceScopedRepository(NavigationMenuItemEntity), + provideWorkspaceScopedRepository(ViewEntity), + provideWorkspaceScopedRepository(PageLayoutEntity), + ], exports: [WorkspaceFlatNavigationMenuItemMapCacheService], }) export class FlatNavigationMenuItemModule {} diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-navigation-menu-item/services/workspace-flat-navigation-menu-item-map-cache.service.ts b/packages/twenty-server/src/engine/metadata-modules/flat-navigation-menu-item/services/workspace-flat-navigation-menu-item-map-cache.service.ts index 7967c3ccb3d..3a483e9ab2d 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-navigation-menu-item/services/workspace-flat-navigation-menu-item-map-cache.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-navigation-menu-item/services/workspace-flat-navigation-menu-item-map-cache.service.ts @@ -14,6 +14,8 @@ import { NavigationMenuItemEntity } from 'src/engine/metadata-modules/navigation import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { PageLayoutEntity } from 'src/engine/metadata-modules/page-layout/entities/page-layout.entity'; import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator'; import { createIdToUniversalIdentifierMap } from 'src/engine/workspace-cache/utils/create-id-to-universal-identifier-map.util'; @@ -21,16 +23,16 @@ import { createIdToUniversalIdentifierMap } from 'src/engine/workspace-cache/uti @WorkspaceCache('flatNavigationMenuItemMaps') export class WorkspaceFlatNavigationMenuItemMapCacheService extends WorkspaceCacheProvider { constructor( - @InjectRepository(NavigationMenuItemEntity) - private readonly navigationMenuItemRepository: Repository, + @InjectWorkspaceScopedRepository(NavigationMenuItemEntity) + private readonly navigationMenuItemRepository: WorkspaceScopedRepository, @InjectRepository(ApplicationEntity) private readonly applicationRepository: Repository, @InjectRepository(ObjectMetadataEntity) private readonly objectMetadataRepository: Repository, - @InjectRepository(ViewEntity) - private readonly viewRepository: Repository, - @InjectRepository(PageLayoutEntity) - private readonly pageLayoutRepository: Repository, + @InjectWorkspaceScopedRepository(ViewEntity) + private readonly viewRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(PageLayoutEntity) + private readonly pageLayoutRepository: WorkspaceScopedRepository, ) { super(); } @@ -45,8 +47,7 @@ export class WorkspaceFlatNavigationMenuItemMapCacheService extends WorkspaceCac views, pageLayouts, ] = await Promise.all([ - this.navigationMenuItemRepository.find({ - where: { workspaceId }, + this.navigationMenuItemRepository.find(workspaceId, { withDeleted: true, }), this.applicationRepository.find({ @@ -59,13 +60,11 @@ export class WorkspaceFlatNavigationMenuItemMapCacheService extends WorkspaceCac select: ['id', 'universalIdentifier'], withDeleted: true, }), - this.viewRepository.find({ - where: { workspaceId }, + this.viewRepository.find(workspaceId, { select: ['id', 'universalIdentifier'], withDeleted: true, }), - this.pageLayoutRepository.find({ - where: { workspaceId }, + this.pageLayoutRepository.find(workspaceId, { select: ['id', 'universalIdentifier'], withDeleted: true, }), diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/services/workspace-flat-object-metadata-map-cache.service.ts b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/services/workspace-flat-object-metadata-map-cache.service.ts index a0eb0f61baa..d57b07b9d67 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/services/workspace-flat-object-metadata-map-cache.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/services/workspace-flat-object-metadata-map-cache.service.ts @@ -15,6 +15,8 @@ import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/ import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { ObjectPermissionEntity } from 'src/engine/metadata-modules/object-permission/object-permission.entity'; import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator'; import { createIdToUniversalIdentifierMap } from 'src/engine/workspace-cache/utils/create-id-to-universal-identifier-map.util'; import { regroupEntitiesByRelatedEntityId } from 'src/engine/workspace-cache/utils/regroup-entities-by-related-entity-id'; @@ -32,12 +34,12 @@ export class WorkspaceFlatObjectMetadataMapCacheService extends WorkspaceCachePr private readonly applicationRepository: Repository, @InjectRepository(FieldMetadataEntity) private readonly fieldMetadataRepository: Repository, - @InjectRepository(IndexMetadataEntity) - private readonly indexMetadataRepository: Repository, - @InjectRepository(ViewEntity) - private readonly viewRepository: Repository, - @InjectRepository(ObjectPermissionEntity) - private readonly objectPermissionRepository: Repository, + @InjectWorkspaceScopedRepository(IndexMetadataEntity) + private readonly indexMetadataRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(ViewEntity) + private readonly viewRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(ObjectPermissionEntity) + private readonly objectPermissionRepository: WorkspaceScopedRepository, ) { super(); } @@ -67,18 +69,15 @@ export class WorkspaceFlatObjectMetadataMapCacheService extends WorkspaceCachePr select: ['id', 'universalIdentifier', 'objectMetadataId'], withDeleted: true, }), - this.indexMetadataRepository.find({ - where: { workspaceId }, + this.indexMetadataRepository.find(workspaceId, { select: ['id', 'universalIdentifier', 'objectMetadataId'], withDeleted: true, }), - this.viewRepository.find({ - where: { workspaceId }, + this.viewRepository.find(workspaceId, { select: ['id', 'universalIdentifier', 'objectMetadataId'], withDeleted: true, }), - this.objectPermissionRepository.find({ - where: { workspaceId }, + this.objectPermissionRepository.find(workspaceId, { select: ['id', 'universalIdentifier', 'objectMetadataId'], withDeleted: true, }), diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-object-permission/services/workspace-flat-object-permission-map-cache.service.ts b/packages/twenty-server/src/engine/metadata-modules/flat-object-permission/services/workspace-flat-object-permission-map-cache.service.ts index 04cc4977611..abe6aaaeba2 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-object-permission/services/workspace-flat-object-permission-map-cache.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-object-permission/services/workspace-flat-object-permission-map-cache.service.ts @@ -10,6 +10,8 @@ import { fromObjectPermissionEntityToFlatObjectPermission } from 'src/engine/met import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { ObjectPermissionEntity } from 'src/engine/metadata-modules/object-permission/object-permission.entity'; import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator'; import { WorkspaceCacheProvider } from 'src/engine/workspace-cache/interfaces/workspace-cache-provider.service'; import { createIdToUniversalIdentifierMap } from 'src/engine/workspace-cache/utils/create-id-to-universal-identifier-map.util'; @@ -19,12 +21,12 @@ import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/ @WorkspaceCache('flatObjectPermissionMaps') export class WorkspaceFlatObjectPermissionMapCacheService extends WorkspaceCacheProvider { constructor( - @InjectRepository(ObjectPermissionEntity) - private readonly objectPermissionRepository: Repository, + @InjectWorkspaceScopedRepository(ObjectPermissionEntity) + private readonly objectPermissionRepository: WorkspaceScopedRepository, @InjectRepository(ApplicationEntity) private readonly applicationRepository: Repository, - @InjectRepository(RoleEntity) - private readonly roleRepository: Repository, + @InjectWorkspaceScopedRepository(RoleEntity) + private readonly roleRepository: WorkspaceScopedRepository, @InjectRepository(ObjectMetadataEntity) private readonly objectMetadataRepository: Repository, ) { @@ -36,8 +38,7 @@ export class WorkspaceFlatObjectPermissionMapCacheService extends WorkspaceCache ): Promise { const [objectPermissions, applications, roles, objectMetadatas] = await Promise.all([ - this.objectPermissionRepository.find({ - where: { workspaceId }, + this.objectPermissionRepository.find(workspaceId, { withDeleted: true, }), this.applicationRepository.find({ @@ -45,8 +46,7 @@ export class WorkspaceFlatObjectPermissionMapCacheService extends WorkspaceCache select: ['id', 'universalIdentifier'], withDeleted: true, }), - this.roleRepository.find({ - where: { workspaceId }, + this.roleRepository.find(workspaceId, { select: ['id', 'universalIdentifier'], withDeleted: true, }), diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-page-layout-tab/flat-page-layout-tab.module.ts b/packages/twenty-server/src/engine/metadata-modules/flat-page-layout-tab/flat-page-layout-tab.module.ts index 0b13a5e9cad..6c3ee01f929 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-page-layout-tab/flat-page-layout-tab.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-page-layout-tab/flat-page-layout-tab.module.ts @@ -7,6 +7,7 @@ import { WorkspaceFlatPageLayoutTabMapCacheService } from 'src/engine/metadata-m import { PageLayoutTabEntity } from 'src/engine/metadata-modules/page-layout-tab/entities/page-layout-tab.entity'; import { PageLayoutWidgetEntity } from 'src/engine/metadata-modules/page-layout-widget/entities/page-layout-widget.entity'; import { PageLayoutEntity } from 'src/engine/metadata-modules/page-layout/entities/page-layout.entity'; +import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/provide-workspace-scoped-repository'; @Module({ imports: [ @@ -18,7 +19,12 @@ import { PageLayoutEntity } from 'src/engine/metadata-modules/page-layout/entiti ]), WorkspaceManyOrAllFlatEntityMapsCacheModule, ], - providers: [WorkspaceFlatPageLayoutTabMapCacheService], + providers: [ + WorkspaceFlatPageLayoutTabMapCacheService, + provideWorkspaceScopedRepository(PageLayoutEntity), + provideWorkspaceScopedRepository(PageLayoutTabEntity), + provideWorkspaceScopedRepository(PageLayoutWidgetEntity), + ], exports: [WorkspaceFlatPageLayoutTabMapCacheService], }) export class FlatPageLayoutTabModule {} diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-page-layout-tab/services/workspace-flat-page-layout-tab-map-cache.service.ts b/packages/twenty-server/src/engine/metadata-modules/flat-page-layout-tab/services/workspace-flat-page-layout-tab-map-cache.service.ts index 8f2e36ea97d..d2fffb05bba 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-page-layout-tab/services/workspace-flat-page-layout-tab-map-cache.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-page-layout-tab/services/workspace-flat-page-layout-tab-map-cache.service.ts @@ -12,6 +12,8 @@ import { transformPageLayoutTabEntityToFlatPageLayoutTab } from 'src/engine/meta import { PageLayoutTabEntity } from 'src/engine/metadata-modules/page-layout-tab/entities/page-layout-tab.entity'; import { PageLayoutWidgetEntity } from 'src/engine/metadata-modules/page-layout-widget/entities/page-layout-widget.entity'; import { PageLayoutEntity } from 'src/engine/metadata-modules/page-layout/entities/page-layout.entity'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator'; import { createIdToUniversalIdentifierMap } from 'src/engine/workspace-cache/utils/create-id-to-universal-identifier-map.util'; import { regroupEntitiesByRelatedEntityId } from 'src/engine/workspace-cache/utils/regroup-entities-by-related-entity-id'; @@ -21,14 +23,14 @@ import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/ @WorkspaceCache('flatPageLayoutTabMaps') export class WorkspaceFlatPageLayoutTabMapCacheService extends WorkspaceCacheProvider { constructor( - @InjectRepository(PageLayoutTabEntity) - private readonly pageLayoutTabRepository: Repository, - @InjectRepository(PageLayoutWidgetEntity) - private readonly pageLayoutWidgetRepository: Repository, + @InjectWorkspaceScopedRepository(PageLayoutTabEntity) + private readonly pageLayoutTabRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(PageLayoutWidgetEntity) + private readonly pageLayoutWidgetRepository: WorkspaceScopedRepository, @InjectRepository(ApplicationEntity) private readonly applicationRepository: Repository, - @InjectRepository(PageLayoutEntity) - private readonly pageLayoutRepository: Repository, + @InjectWorkspaceScopedRepository(PageLayoutEntity) + private readonly pageLayoutRepository: WorkspaceScopedRepository, ) { super(); } @@ -36,12 +38,10 @@ export class WorkspaceFlatPageLayoutTabMapCacheService extends WorkspaceCachePro async computeForCache(workspaceId: string): Promise { const [pageLayoutTabs, pageLayoutWidgets, applications, pageLayouts] = await Promise.all([ - this.pageLayoutTabRepository.find({ - where: { workspaceId }, + this.pageLayoutTabRepository.find(workspaceId, { withDeleted: true, }), - this.pageLayoutWidgetRepository.find({ - where: { workspaceId }, + this.pageLayoutWidgetRepository.find(workspaceId, { select: ['id', 'universalIdentifier', 'pageLayoutTabId'], withDeleted: true, }), @@ -50,8 +50,7 @@ export class WorkspaceFlatPageLayoutTabMapCacheService extends WorkspaceCachePro select: ['id', 'universalIdentifier'], withDeleted: true, }), - this.pageLayoutRepository.find({ - where: { workspaceId }, + this.pageLayoutRepository.find(workspaceId, { select: ['id', 'universalIdentifier'], withDeleted: true, }), diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-page-layout-widget/flat-page-layout-widget.module.ts b/packages/twenty-server/src/engine/metadata-modules/flat-page-layout-widget/flat-page-layout-widget.module.ts index 1cfc697817d..3c972ad78e1 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-page-layout-widget/flat-page-layout-widget.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-page-layout-widget/flat-page-layout-widget.module.ts @@ -10,6 +10,7 @@ import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadat import { PageLayoutTabEntity } from 'src/engine/metadata-modules/page-layout-tab/entities/page-layout-tab.entity'; import { PageLayoutWidgetEntity } from 'src/engine/metadata-modules/page-layout-widget/entities/page-layout-widget.entity'; import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity'; +import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/provide-workspace-scoped-repository'; @Module({ imports: [ @@ -26,6 +27,9 @@ import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entit providers: [ WorkspaceFlatPageLayoutWidgetMapCacheService, FlatPageLayoutWidgetTypeValidatorService, + provideWorkspaceScopedRepository(PageLayoutTabEntity), + provideWorkspaceScopedRepository(PageLayoutWidgetEntity), + provideWorkspaceScopedRepository(ViewEntity), ], exports: [ WorkspaceFlatPageLayoutWidgetMapCacheService, diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-page-layout-widget/services/workspace-flat-page-layout-widget-map-cache.service.ts b/packages/twenty-server/src/engine/metadata-modules/flat-page-layout-widget/services/workspace-flat-page-layout-widget-map-cache.service.ts index 17fa17c9164..83adce7cab5 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-page-layout-widget/services/workspace-flat-page-layout-widget-map-cache.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-page-layout-widget/services/workspace-flat-page-layout-widget-map-cache.service.ts @@ -15,6 +15,8 @@ import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadat import { PageLayoutTabEntity } from 'src/engine/metadata-modules/page-layout-tab/entities/page-layout-tab.entity'; import { PageLayoutWidgetEntity } from 'src/engine/metadata-modules/page-layout-widget/entities/page-layout-widget.entity'; import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator'; import { createIdToUniversalIdentifierMap } from 'src/engine/workspace-cache/utils/create-id-to-universal-identifier-map.util'; import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/workspace-manager/workspace-migration/utils/add-flat-entity-to-flat-entity-maps-through-mutation-or-throw.util'; @@ -23,20 +25,20 @@ import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/ @WorkspaceCache('flatPageLayoutWidgetMaps') export class WorkspaceFlatPageLayoutWidgetMapCacheService extends WorkspaceCacheProvider { constructor( - @InjectRepository(PageLayoutWidgetEntity) - private readonly pageLayoutWidgetRepository: Repository, + @InjectWorkspaceScopedRepository(PageLayoutWidgetEntity) + private readonly pageLayoutWidgetRepository: WorkspaceScopedRepository, @InjectRepository(ApplicationEntity) private readonly applicationRepository: Repository, - @InjectRepository(PageLayoutTabEntity) - private readonly pageLayoutTabRepository: Repository, + @InjectWorkspaceScopedRepository(PageLayoutTabEntity) + private readonly pageLayoutTabRepository: WorkspaceScopedRepository, @InjectRepository(ObjectMetadataEntity) private readonly objectMetadataRepository: Repository, @InjectRepository(FieldMetadataEntity) private readonly fieldMetadataRepository: Repository, @InjectRepository(FrontComponentEntity) private readonly frontComponentRepository: Repository, - @InjectRepository(ViewEntity) - private readonly viewRepository: Repository, + @InjectWorkspaceScopedRepository(ViewEntity) + private readonly viewRepository: WorkspaceScopedRepository, ) { super(); } @@ -53,8 +55,7 @@ export class WorkspaceFlatPageLayoutWidgetMapCacheService extends WorkspaceCache frontComponents, views, ] = await Promise.all([ - this.pageLayoutWidgetRepository.find({ - where: { workspaceId }, + this.pageLayoutWidgetRepository.find(workspaceId, { withDeleted: true, }), this.applicationRepository.find({ @@ -62,8 +63,7 @@ export class WorkspaceFlatPageLayoutWidgetMapCacheService extends WorkspaceCache select: ['id', 'universalIdentifier'], withDeleted: true, }), - this.pageLayoutTabRepository.find({ - where: { workspaceId }, + this.pageLayoutTabRepository.find(workspaceId, { select: ['id', 'universalIdentifier'], withDeleted: true, }), @@ -82,8 +82,7 @@ export class WorkspaceFlatPageLayoutWidgetMapCacheService extends WorkspaceCache select: ['id', 'universalIdentifier'], withDeleted: true, }), - this.viewRepository.find({ - where: { workspaceId }, + this.viewRepository.find(workspaceId, { select: ['id', 'universalIdentifier'], withDeleted: true, }), diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-page-layout/flat-page-layout.module.ts b/packages/twenty-server/src/engine/metadata-modules/flat-page-layout/flat-page-layout.module.ts index de8d1ea7e37..b6d634ca351 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-page-layout/flat-page-layout.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-page-layout/flat-page-layout.module.ts @@ -6,6 +6,7 @@ import { WorkspaceFlatPageLayoutMapCacheService } from 'src/engine/metadata-modu import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { PageLayoutTabEntity } from 'src/engine/metadata-modules/page-layout-tab/entities/page-layout-tab.entity'; import { PageLayoutEntity } from 'src/engine/metadata-modules/page-layout/entities/page-layout.entity'; +import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/provide-workspace-scoped-repository'; @Module({ imports: [ @@ -16,7 +17,11 @@ import { PageLayoutEntity } from 'src/engine/metadata-modules/page-layout/entiti ObjectMetadataEntity, ]), ], - providers: [WorkspaceFlatPageLayoutMapCacheService], + providers: [ + WorkspaceFlatPageLayoutMapCacheService, + provideWorkspaceScopedRepository(PageLayoutEntity), + provideWorkspaceScopedRepository(PageLayoutTabEntity), + ], exports: [WorkspaceFlatPageLayoutMapCacheService], }) export class FlatPageLayoutModule {} diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-page-layout/services/workspace-flat-page-layout-map-cache.service.ts b/packages/twenty-server/src/engine/metadata-modules/flat-page-layout/services/workspace-flat-page-layout-map-cache.service.ts index e43e68fc90f..0a571758278 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-page-layout/services/workspace-flat-page-layout-map-cache.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-page-layout/services/workspace-flat-page-layout-map-cache.service.ts @@ -12,6 +12,8 @@ import { transformPageLayoutEntityToFlatPageLayout } from 'src/engine/metadata-m import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { PageLayoutTabEntity } from 'src/engine/metadata-modules/page-layout-tab/entities/page-layout-tab.entity'; import { PageLayoutEntity } from 'src/engine/metadata-modules/page-layout/entities/page-layout.entity'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator'; import { createIdToUniversalIdentifierMap } from 'src/engine/workspace-cache/utils/create-id-to-universal-identifier-map.util'; import { regroupEntitiesByRelatedEntityId } from 'src/engine/workspace-cache/utils/regroup-entities-by-related-entity-id'; @@ -21,10 +23,10 @@ import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/ @WorkspaceCache('flatPageLayoutMaps') export class WorkspaceFlatPageLayoutMapCacheService extends WorkspaceCacheProvider { constructor( - @InjectRepository(PageLayoutEntity) - private readonly pageLayoutRepository: Repository, - @InjectRepository(PageLayoutTabEntity) - private readonly pageLayoutTabRepository: Repository, + @InjectWorkspaceScopedRepository(PageLayoutEntity) + private readonly pageLayoutRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(PageLayoutTabEntity) + private readonly pageLayoutTabRepository: WorkspaceScopedRepository, @InjectRepository(ApplicationEntity) private readonly applicationRepository: Repository, @InjectRepository(ObjectMetadataEntity) @@ -36,12 +38,10 @@ export class WorkspaceFlatPageLayoutMapCacheService extends WorkspaceCacheProvid async computeForCache(workspaceId: string): Promise { const [pageLayouts, pageLayoutTabs, applications, objectMetadatas] = await Promise.all([ - this.pageLayoutRepository.find({ - where: { workspaceId }, + this.pageLayoutRepository.find(workspaceId, { withDeleted: true, }), - this.pageLayoutTabRepository.find({ - where: { workspaceId }, + this.pageLayoutTabRepository.find(workspaceId, { select: ['id', 'universalIdentifier', 'pageLayoutId'], withDeleted: true, }), diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-permission-flag/flat-permission-flag.module.ts b/packages/twenty-server/src/engine/metadata-modules/flat-permission-flag/flat-permission-flag.module.ts index ae24c38f0bc..cb513e34fe1 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-permission-flag/flat-permission-flag.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-permission-flag/flat-permission-flag.module.ts @@ -6,6 +6,7 @@ import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata import { WorkspaceFlatPermissionFlagMapCacheService } from 'src/engine/metadata-modules/flat-permission-flag/services/workspace-flat-permission-flag-map-cache.service'; import { PermissionFlagEntity } from 'src/engine/metadata-modules/permission-flag/permission-flag.entity'; import { RolePermissionFlagEntity } from 'src/engine/metadata-modules/role-permission-flag/role-permission-flag.entity'; +import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/provide-workspace-scoped-repository'; @Module({ imports: [ @@ -16,7 +17,10 @@ import { RolePermissionFlagEntity } from 'src/engine/metadata-modules/role-permi ]), WorkspaceManyOrAllFlatEntityMapsCacheModule, ], - providers: [WorkspaceFlatPermissionFlagMapCacheService], + providers: [ + WorkspaceFlatPermissionFlagMapCacheService, + provideWorkspaceScopedRepository(PermissionFlagEntity), + ], exports: [WorkspaceFlatPermissionFlagMapCacheService], }) export class FlatPermissionFlagModule {} diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-permission-flag/services/workspace-flat-permission-flag-map-cache.service.ts b/packages/twenty-server/src/engine/metadata-modules/flat-permission-flag/services/workspace-flat-permission-flag-map-cache.service.ts index e7fcbf9bdf9..c8de11b0cb0 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-permission-flag/services/workspace-flat-permission-flag-map-cache.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-permission-flag/services/workspace-flat-permission-flag-map-cache.service.ts @@ -9,6 +9,8 @@ import { type FlatPermissionFlagMaps } from 'src/engine/metadata-modules/flat-pe import { fromPermissionFlagEntityToFlatPermissionFlag } from 'src/engine/metadata-modules/flat-permission-flag/utils/from-permission-flag-entity-to-flat-permission-flag.util'; import { PermissionFlagEntity } from 'src/engine/metadata-modules/permission-flag/permission-flag.entity'; import { RolePermissionFlagEntity } from 'src/engine/metadata-modules/role-permission-flag/role-permission-flag.entity'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator'; import { WorkspaceCacheProvider } from 'src/engine/workspace-cache/interfaces/workspace-cache-provider.service'; import { createIdToUniversalIdentifierMap } from 'src/engine/workspace-cache/utils/create-id-to-universal-identifier-map.util'; @@ -19,8 +21,8 @@ import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/ @WorkspaceCache('flatPermissionFlagMaps') export class WorkspaceFlatPermissionFlagMapCacheService extends WorkspaceCacheProvider { constructor( - @InjectRepository(PermissionFlagEntity) - private readonly permissionFlagRepository: Repository, + @InjectWorkspaceScopedRepository(PermissionFlagEntity) + private readonly permissionFlagRepository: WorkspaceScopedRepository, @InjectRepository(ApplicationEntity) private readonly applicationRepository: Repository, @InjectRepository(RolePermissionFlagEntity) @@ -32,8 +34,7 @@ export class WorkspaceFlatPermissionFlagMapCacheService extends WorkspaceCachePr async computeForCache(workspaceId: string): Promise { const [permissionFlags, applications, rolePermissionFlags] = await Promise.all([ - this.permissionFlagRepository.find({ - where: { workspaceId }, + this.permissionFlagRepository.find(workspaceId, { withDeleted: true, }), this.applicationRepository.find({ diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-role-permission-flag/services/workspace-flat-role-permission-flag-map-cache.service.ts b/packages/twenty-server/src/engine/metadata-modules/flat-role-permission-flag/services/workspace-flat-role-permission-flag-map-cache.service.ts index 979f11f796a..adb4a390758 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-role-permission-flag/services/workspace-flat-role-permission-flag-map-cache.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-role-permission-flag/services/workspace-flat-role-permission-flag-map-cache.service.ts @@ -10,6 +10,8 @@ import { fromRolePermissionFlagEntityToFlatRolePermissionFlag } from 'src/engine import { PermissionFlagEntity } from 'src/engine/metadata-modules/permission-flag/permission-flag.entity'; import { RolePermissionFlagEntity } from 'src/engine/metadata-modules/role-permission-flag/role-permission-flag.entity'; import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCacheProvider } from 'src/engine/workspace-cache/interfaces/workspace-cache-provider.service'; import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator'; import { createIdToUniversalIdentifierMap } from 'src/engine/workspace-cache/utils/create-id-to-universal-identifier-map.util'; @@ -23,10 +25,10 @@ export class WorkspaceFlatRolePermissionFlagMapCacheService extends WorkspaceCac private readonly rolePermissionFlagRepository: Repository, @InjectRepository(ApplicationEntity) private readonly applicationRepository: Repository, - @InjectRepository(RoleEntity) - private readonly roleRepository: Repository, - @InjectRepository(PermissionFlagEntity) - private readonly permissionFlagRepository: Repository, + @InjectWorkspaceScopedRepository(RoleEntity) + private readonly roleRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(PermissionFlagEntity) + private readonly permissionFlagRepository: WorkspaceScopedRepository, ) { super(); } @@ -45,13 +47,11 @@ export class WorkspaceFlatRolePermissionFlagMapCacheService extends WorkspaceCac select: ['id', 'universalIdentifier'], withDeleted: true, }), - this.roleRepository.find({ - where: { workspaceId }, + this.roleRepository.find(workspaceId, { select: ['id', 'universalIdentifier'], withDeleted: true, }), - this.permissionFlagRepository.find({ - where: { workspaceId }, + this.permissionFlagRepository.find(workspaceId, { select: ['id', 'universalIdentifier'], withDeleted: true, }), diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-role-target/services/workspace-flat-role-target-map-cache.service.ts b/packages/twenty-server/src/engine/metadata-modules/flat-role-target/services/workspace-flat-role-target-map-cache.service.ts index 3bd1f9a1324..764eceb3bda 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-role-target/services/workspace-flat-role-target-map-cache.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-role-target/services/workspace-flat-role-target-map-cache.service.ts @@ -11,6 +11,8 @@ import { type FlatRoleTargetMaps } from 'src/engine/metadata-modules/flat-role-t import { fromRoleTargetEntityToFlatRoleTarget } from 'src/engine/metadata-modules/flat-role-target/utils/from-role-target-entity-to-flat-role-target.util'; import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; import { RoleTargetEntity } from 'src/engine/metadata-modules/role-target/role-target.entity'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator'; import { createIdToUniversalIdentifierMap } from 'src/engine/workspace-cache/utils/create-id-to-universal-identifier-map.util'; import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/workspace-manager/workspace-migration/utils/add-flat-entity-to-flat-entity-maps-through-mutation-or-throw.util'; @@ -19,20 +21,19 @@ import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/ @WorkspaceCache('flatRoleTargetMaps') export class WorkspaceFlatRoleTargetMapCacheService extends WorkspaceCacheProvider { constructor( - @InjectRepository(RoleTargetEntity) - private readonly roleTargetRepository: Repository, + @InjectWorkspaceScopedRepository(RoleTargetEntity) + private readonly roleTargetRepository: WorkspaceScopedRepository, @InjectRepository(ApplicationEntity) private readonly applicationRepository: Repository, - @InjectRepository(RoleEntity) - private readonly roleRepository: Repository, + @InjectWorkspaceScopedRepository(RoleEntity) + private readonly roleRepository: WorkspaceScopedRepository, ) { super(); } async computeForCache(workspaceId: string): Promise { const [roleTargets, applications, roles] = await Promise.all([ - this.roleTargetRepository.find({ - where: { workspaceId }, + this.roleTargetRepository.find(workspaceId, { withDeleted: true, }), this.applicationRepository.find({ @@ -40,8 +41,7 @@ export class WorkspaceFlatRoleTargetMapCacheService extends WorkspaceCacheProvid select: ['id', 'universalIdentifier'], withDeleted: true, }), - this.roleRepository.find({ - where: { workspaceId }, + this.roleRepository.find(workspaceId, { select: ['id', 'universalIdentifier'], withDeleted: true, }), diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-row-level-permission-predicate/services/workspace-flat-row-level-permission-predicate-group-map-cache.service.ts b/packages/twenty-server/src/engine/metadata-modules/flat-row-level-permission-predicate/services/workspace-flat-row-level-permission-predicate-group-map-cache.service.ts index c494e2b1b9d..9adfa3830bf 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-row-level-permission-predicate/services/workspace-flat-row-level-permission-predicate-group-map-cache.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-row-level-permission-predicate/services/workspace-flat-row-level-permission-predicate-group-map-cache.service.ts @@ -15,6 +15,8 @@ import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; import { RowLevelPermissionPredicateGroupEntity } from 'src/engine/metadata-modules/row-level-permission-predicate/entities/row-level-permission-predicate-group.entity'; import { RowLevelPermissionPredicateEntity } from 'src/engine/metadata-modules/row-level-permission-predicate/entities/row-level-permission-predicate.entity'; import { type FlatRowLevelPermissionPredicateGroupMaps } from 'src/engine/metadata-modules/row-level-permission-predicate/types/flat-row-level-permission-predicate-group-maps.type'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator'; import { createIdToUniversalIdentifierMap } from 'src/engine/workspace-cache/utils/create-id-to-universal-identifier-map.util'; import { regroupEntitiesByRelatedEntityId } from 'src/engine/workspace-cache/utils/regroup-entities-by-related-entity-id'; @@ -24,16 +26,16 @@ import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/ @WorkspaceCache('flatRowLevelPermissionPredicateGroupMaps') export class WorkspaceFlatRowLevelPermissionPredicateGroupMapCacheService extends WorkspaceCacheProvider { constructor( - @InjectRepository(RowLevelPermissionPredicateGroupEntity) - private readonly rowLevelPermissionPredicateGroupRepository: Repository, + @InjectWorkspaceScopedRepository(RowLevelPermissionPredicateGroupEntity) + private readonly rowLevelPermissionPredicateGroupRepository: WorkspaceScopedRepository, @InjectRepository(ApplicationEntity) private readonly applicationRepository: Repository, @InjectRepository(ObjectMetadataEntity) private readonly objectMetadataRepository: Repository, - @InjectRepository(RoleEntity) - private readonly roleRepository: Repository, - @InjectRepository(RowLevelPermissionPredicateEntity) - private readonly rowLevelPermissionPredicateRepository: Repository, + @InjectWorkspaceScopedRepository(RoleEntity) + private readonly roleRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(RowLevelPermissionPredicateEntity) + private readonly rowLevelPermissionPredicateRepository: WorkspaceScopedRepository, ) { super(); } @@ -48,8 +50,7 @@ export class WorkspaceFlatRowLevelPermissionPredicateGroupMapCacheService extend roles, rowLevelPermissionPredicates, ] = await Promise.all([ - this.rowLevelPermissionPredicateGroupRepository.find({ - where: { workspaceId }, + this.rowLevelPermissionPredicateGroupRepository.find(workspaceId, { withDeleted: true, }), this.applicationRepository.find({ @@ -62,13 +63,11 @@ export class WorkspaceFlatRowLevelPermissionPredicateGroupMapCacheService extend select: ['id', 'universalIdentifier'], withDeleted: true, }), - this.roleRepository.find({ - where: { workspaceId }, + this.roleRepository.find(workspaceId, { select: ['id', 'universalIdentifier'], withDeleted: true, }), - this.rowLevelPermissionPredicateRepository.find({ - where: { workspaceId }, + this.rowLevelPermissionPredicateRepository.find(workspaceId, { select: [ 'id', 'universalIdentifier', diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-row-level-permission-predicate/services/workspace-flat-row-level-permission-predicate-map-cache.service.ts b/packages/twenty-server/src/engine/metadata-modules/flat-row-level-permission-predicate/services/workspace-flat-row-level-permission-predicate-map-cache.service.ts index 436e4decb2c..8ff6f312498 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-row-level-permission-predicate/services/workspace-flat-row-level-permission-predicate-map-cache.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-row-level-permission-predicate/services/workspace-flat-row-level-permission-predicate-map-cache.service.ts @@ -16,6 +16,8 @@ import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; import { RowLevelPermissionPredicateGroupEntity } from 'src/engine/metadata-modules/row-level-permission-predicate/entities/row-level-permission-predicate-group.entity'; import { RowLevelPermissionPredicateEntity } from 'src/engine/metadata-modules/row-level-permission-predicate/entities/row-level-permission-predicate.entity'; import { type FlatRowLevelPermissionPredicateMaps } from 'src/engine/metadata-modules/row-level-permission-predicate/types/flat-row-level-permission-predicate-maps.type'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator'; import { createIdToUniversalIdentifierMap } from 'src/engine/workspace-cache/utils/create-id-to-universal-identifier-map.util'; import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/workspace-manager/workspace-migration/utils/add-flat-entity-to-flat-entity-maps-through-mutation-or-throw.util'; @@ -24,18 +26,18 @@ import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/ @WorkspaceCache('flatRowLevelPermissionPredicateMaps') export class WorkspaceFlatRowLevelPermissionPredicateMapCacheService extends WorkspaceCacheProvider { constructor( - @InjectRepository(RowLevelPermissionPredicateEntity) - private readonly rowLevelPermissionPredicateRepository: Repository, + @InjectWorkspaceScopedRepository(RowLevelPermissionPredicateEntity) + private readonly rowLevelPermissionPredicateRepository: WorkspaceScopedRepository, @InjectRepository(ApplicationEntity) private readonly applicationRepository: Repository, @InjectRepository(FieldMetadataEntity) private readonly fieldMetadataRepository: Repository, @InjectRepository(ObjectMetadataEntity) private readonly objectMetadataRepository: Repository, - @InjectRepository(RoleEntity) - private readonly roleRepository: Repository, - @InjectRepository(RowLevelPermissionPredicateGroupEntity) - private readonly rowLevelPermissionPredicateGroupRepository: Repository, + @InjectWorkspaceScopedRepository(RoleEntity) + private readonly roleRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(RowLevelPermissionPredicateGroupEntity) + private readonly rowLevelPermissionPredicateGroupRepository: WorkspaceScopedRepository, ) { super(); } @@ -51,8 +53,7 @@ export class WorkspaceFlatRowLevelPermissionPredicateMapCacheService extends Wor roles, rowLevelPermissionPredicateGroups, ] = await Promise.all([ - this.rowLevelPermissionPredicateRepository.find({ - where: { workspaceId }, + this.rowLevelPermissionPredicateRepository.find(workspaceId, { withDeleted: true, }), this.applicationRepository.find({ @@ -70,13 +71,11 @@ export class WorkspaceFlatRowLevelPermissionPredicateMapCacheService extends Wor select: ['id', 'universalIdentifier'], withDeleted: true, }), - this.roleRepository.find({ - where: { workspaceId }, + this.roleRepository.find(workspaceId, { select: ['id', 'universalIdentifier'], withDeleted: true, }), - this.rowLevelPermissionPredicateGroupRepository.find({ - where: { workspaceId }, + this.rowLevelPermissionPredicateGroupRepository.find(workspaceId, { select: ['id', 'universalIdentifier'], withDeleted: true, }), diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-skill/flat-skill.module.ts b/packages/twenty-server/src/engine/metadata-modules/flat-skill/flat-skill.module.ts index dc0817bb82c..d096f99d0b7 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-skill/flat-skill.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-skill/flat-skill.module.ts @@ -5,13 +5,17 @@ import { ApplicationEntity } from 'src/engine/core-modules/application/applicati import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module'; import { WorkspaceFlatSkillMapCacheService } from 'src/engine/metadata-modules/flat-skill/services/workspace-flat-skill-map-cache.service'; import { SkillEntity } from 'src/engine/metadata-modules/skill/entities/skill.entity'; +import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/provide-workspace-scoped-repository'; @Module({ imports: [ TypeOrmModule.forFeature([ApplicationEntity, SkillEntity]), WorkspaceManyOrAllFlatEntityMapsCacheModule, ], - providers: [WorkspaceFlatSkillMapCacheService], + providers: [ + WorkspaceFlatSkillMapCacheService, + provideWorkspaceScopedRepository(SkillEntity), + ], exports: [WorkspaceFlatSkillMapCacheService], }) export class FlatSkillModule {} diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-skill/services/workspace-flat-skill-map-cache.service.ts b/packages/twenty-server/src/engine/metadata-modules/flat-skill/services/workspace-flat-skill-map-cache.service.ts index 601c9ee4f11..c5b9ddb793a 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-skill/services/workspace-flat-skill-map-cache.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-skill/services/workspace-flat-skill-map-cache.service.ts @@ -10,6 +10,8 @@ import { createEmptyFlatEntityMaps } from 'src/engine/metadata-modules/flat-enti import { type FlatSkillMaps } from 'src/engine/metadata-modules/flat-skill/types/flat-skill-maps.type'; import { fromSkillEntityToFlatSkill } from 'src/engine/metadata-modules/flat-skill/utils/from-skill-entity-to-flat-skill.util'; import { SkillEntity } from 'src/engine/metadata-modules/skill/entities/skill.entity'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator'; import { createIdToUniversalIdentifierMap } from 'src/engine/workspace-cache/utils/create-id-to-universal-identifier-map.util'; import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/workspace-manager/workspace-migration/utils/add-flat-entity-to-flat-entity-maps-through-mutation-or-throw.util'; @@ -18,8 +20,8 @@ import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/ @WorkspaceCache('flatSkillMaps') export class WorkspaceFlatSkillMapCacheService extends WorkspaceCacheProvider { constructor( - @InjectRepository(SkillEntity) - private readonly skillRepository: Repository, + @InjectWorkspaceScopedRepository(SkillEntity) + private readonly skillRepository: WorkspaceScopedRepository, @InjectRepository(ApplicationEntity) private readonly applicationRepository: Repository, ) { @@ -28,8 +30,7 @@ export class WorkspaceFlatSkillMapCacheService extends WorkspaceCacheProvider { const [skills, applications] = await Promise.all([ - this.skillRepository.find({ - where: { workspaceId }, + this.skillRepository.find(workspaceId, { withDeleted: true, }), this.applicationRepository.find({ diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-view-field-group/services/workspace-flat-view-field-group-map-cache.service.ts b/packages/twenty-server/src/engine/metadata-modules/flat-view-field-group/services/workspace-flat-view-field-group-map-cache.service.ts index d8be2c79bc6..3e2f0b0319e 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-view-field-group/services/workspace-flat-view-field-group-map-cache.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-view-field-group/services/workspace-flat-view-field-group-map-cache.service.ts @@ -12,6 +12,8 @@ import { fromViewFieldGroupEntityToFlatViewFieldGroup } from 'src/engine/metadat import { ViewFieldGroupEntity } from 'src/engine/metadata-modules/view-field-group/entities/view-field-group.entity'; import { ViewFieldEntity } from 'src/engine/metadata-modules/view-field/entities/view-field.entity'; import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator'; import { createIdToUniversalIdentifierMap } from 'src/engine/workspace-cache/utils/create-id-to-universal-identifier-map.util'; import { regroupEntitiesByRelatedEntityId } from 'src/engine/workspace-cache/utils/regroup-entities-by-related-entity-id'; @@ -21,14 +23,14 @@ import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/ @WorkspaceCache('flatViewFieldGroupMaps') export class WorkspaceFlatViewFieldGroupMapCacheService extends WorkspaceCacheProvider { constructor( - @InjectRepository(ViewFieldGroupEntity) - private readonly viewFieldGroupRepository: Repository, + @InjectWorkspaceScopedRepository(ViewFieldGroupEntity) + private readonly viewFieldGroupRepository: WorkspaceScopedRepository, @InjectRepository(ApplicationEntity) private readonly applicationRepository: Repository, - @InjectRepository(ViewEntity) - private readonly viewRepository: Repository, - @InjectRepository(ViewFieldEntity) - private readonly viewFieldRepository: Repository, + @InjectWorkspaceScopedRepository(ViewEntity) + private readonly viewRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(ViewFieldEntity) + private readonly viewFieldRepository: WorkspaceScopedRepository, ) { super(); } @@ -36,8 +38,7 @@ export class WorkspaceFlatViewFieldGroupMapCacheService extends WorkspaceCachePr async computeForCache(workspaceId: string): Promise { const [viewFieldGroups, applications, views, viewFields] = await Promise.all([ - this.viewFieldGroupRepository.find({ - where: { workspaceId }, + this.viewFieldGroupRepository.find(workspaceId, { withDeleted: true, }), this.applicationRepository.find({ @@ -45,13 +46,11 @@ export class WorkspaceFlatViewFieldGroupMapCacheService extends WorkspaceCachePr select: ['id', 'universalIdentifier'], withDeleted: true, }), - this.viewRepository.find({ - where: { workspaceId }, + this.viewRepository.find(workspaceId, { select: ['id', 'universalIdentifier'], withDeleted: true, }), - this.viewFieldRepository.find({ - where: { workspaceId }, + this.viewFieldRepository.find(workspaceId, { select: ['id', 'universalIdentifier', 'viewFieldGroupId'], withDeleted: true, }), diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-view-field/services/workspace-flat-view-field-map-cache.service.ts b/packages/twenty-server/src/engine/metadata-modules/flat-view-field/services/workspace-flat-view-field-map-cache.service.ts index abf036f5742..dd47654d633 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-view-field/services/workspace-flat-view-field-map-cache.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-view-field/services/workspace-flat-view-field-map-cache.service.ts @@ -13,6 +13,8 @@ import { fromViewFieldEntityToFlatViewField } from 'src/engine/metadata-modules/ import { ViewFieldGroupEntity } from 'src/engine/metadata-modules/view-field-group/entities/view-field-group.entity'; import { ViewFieldEntity } from 'src/engine/metadata-modules/view-field/entities/view-field.entity'; import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator'; import { createIdToUniversalIdentifierMap } from 'src/engine/workspace-cache/utils/create-id-to-universal-identifier-map.util'; import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/workspace-manager/workspace-migration/utils/add-flat-entity-to-flat-entity-maps-through-mutation-or-throw.util'; @@ -21,16 +23,16 @@ import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/ @WorkspaceCache('flatViewFieldMaps') export class WorkspaceFlatViewFieldMapCacheService extends WorkspaceCacheProvider { constructor( - @InjectRepository(ViewFieldEntity) - private readonly viewFieldRepository: Repository, + @InjectWorkspaceScopedRepository(ViewFieldEntity) + private readonly viewFieldRepository: WorkspaceScopedRepository, @InjectRepository(ApplicationEntity) private readonly applicationRepository: Repository, @InjectRepository(FieldMetadataEntity) private readonly fieldMetadataRepository: Repository, - @InjectRepository(ViewEntity) - private readonly viewRepository: Repository, - @InjectRepository(ViewFieldGroupEntity) - private readonly viewFieldGroupRepository: Repository, + @InjectWorkspaceScopedRepository(ViewEntity) + private readonly viewRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(ViewFieldGroupEntity) + private readonly viewFieldGroupRepository: WorkspaceScopedRepository, ) { super(); } @@ -38,8 +40,7 @@ export class WorkspaceFlatViewFieldMapCacheService extends WorkspaceCacheProvide async computeForCache(workspaceId: string): Promise { const [viewFields, applications, fieldMetadatas, views, viewFieldGroups] = await Promise.all([ - this.viewFieldRepository.find({ - where: { workspaceId }, + this.viewFieldRepository.find(workspaceId, { withDeleted: true, }), this.applicationRepository.find({ @@ -52,13 +53,11 @@ export class WorkspaceFlatViewFieldMapCacheService extends WorkspaceCacheProvide select: ['id', 'universalIdentifier'], withDeleted: true, }), - this.viewRepository.find({ - where: { workspaceId }, + this.viewRepository.find(workspaceId, { select: ['id', 'universalIdentifier'], withDeleted: true, }), - this.viewFieldGroupRepository.find({ - where: { workspaceId }, + this.viewFieldGroupRepository.find(workspaceId, { select: ['id', 'universalIdentifier'], withDeleted: true, }), diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-view-filter-group/services/workspace-flat-view-filter-group-map-cache.service.ts b/packages/twenty-server/src/engine/metadata-modules/flat-view-filter-group/services/workspace-flat-view-filter-group-map-cache.service.ts index 6ea6266bfa9..d478912211b 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-view-filter-group/services/workspace-flat-view-filter-group-map-cache.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-view-filter-group/services/workspace-flat-view-filter-group-map-cache.service.ts @@ -12,6 +12,8 @@ import { fromViewFilterGroupEntityToFlatViewFilterGroup } from 'src/engine/metad import { ViewFilterGroupEntity } from 'src/engine/metadata-modules/view-filter-group/entities/view-filter-group.entity'; import { ViewFilterEntity } from 'src/engine/metadata-modules/view-filter/entities/view-filter.entity'; import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator'; import { createIdToUniversalIdentifierMap } from 'src/engine/workspace-cache/utils/create-id-to-universal-identifier-map.util'; import { regroupEntitiesByRelatedEntityId } from 'src/engine/workspace-cache/utils/regroup-entities-by-related-entity-id'; @@ -21,14 +23,14 @@ import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/ @WorkspaceCache('flatViewFilterGroupMaps') export class WorkspaceFlatViewFilterGroupMapCacheService extends WorkspaceCacheProvider { constructor( - @InjectRepository(ViewFilterGroupEntity) - private readonly viewFilterGroupRepository: Repository, + @InjectWorkspaceScopedRepository(ViewFilterGroupEntity) + private readonly viewFilterGroupRepository: WorkspaceScopedRepository, @InjectRepository(ApplicationEntity) private readonly applicationRepository: Repository, - @InjectRepository(ViewFilterEntity) - private readonly viewFilterRepository: Repository, - @InjectRepository(ViewEntity) - private readonly viewRepository: Repository, + @InjectWorkspaceScopedRepository(ViewFilterEntity) + private readonly viewFilterRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(ViewEntity) + private readonly viewRepository: WorkspaceScopedRepository, ) { super(); } @@ -36,8 +38,7 @@ export class WorkspaceFlatViewFilterGroupMapCacheService extends WorkspaceCacheP async computeForCache(workspaceId: string): Promise { const [viewFilterGroups, applications, viewFilters, views] = await Promise.all([ - this.viewFilterGroupRepository.find({ - where: { workspaceId }, + this.viewFilterGroupRepository.find(workspaceId, { withDeleted: true, }), this.applicationRepository.find({ @@ -45,13 +46,11 @@ export class WorkspaceFlatViewFilterGroupMapCacheService extends WorkspaceCacheP select: ['id', 'universalIdentifier'], withDeleted: true, }), - this.viewFilterRepository.find({ - where: { workspaceId }, + this.viewFilterRepository.find(workspaceId, { select: ['id', 'universalIdentifier', 'viewFilterGroupId'], withDeleted: true, }), - this.viewRepository.find({ - where: { workspaceId }, + this.viewRepository.find(workspaceId, { select: ['id', 'universalIdentifier'], withDeleted: true, }), diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-view-filter/services/workspace-flat-view-filter-map-cache.service.ts b/packages/twenty-server/src/engine/metadata-modules/flat-view-filter/services/workspace-flat-view-filter-map-cache.service.ts index 3366e87468b..d4af2ecf7d3 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-view-filter/services/workspace-flat-view-filter-map-cache.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-view-filter/services/workspace-flat-view-filter-map-cache.service.ts @@ -13,6 +13,8 @@ import { fromViewFilterEntityToFlatViewFilter } from 'src/engine/metadata-module import { ViewFilterGroupEntity } from 'src/engine/metadata-modules/view-filter-group/entities/view-filter-group.entity'; import { ViewFilterEntity } from 'src/engine/metadata-modules/view-filter/entities/view-filter.entity'; import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator'; import { createIdToUniversalIdentifierMap } from 'src/engine/workspace-cache/utils/create-id-to-universal-identifier-map.util'; import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/workspace-manager/workspace-migration/utils/add-flat-entity-to-flat-entity-maps-through-mutation-or-throw.util'; @@ -21,16 +23,16 @@ import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/ @WorkspaceCache('flatViewFilterMaps') export class WorkspaceFlatViewFilterMapCacheService extends WorkspaceCacheProvider { constructor( - @InjectRepository(ViewFilterEntity) - private readonly viewFilterRepository: Repository, + @InjectWorkspaceScopedRepository(ViewFilterEntity) + private readonly viewFilterRepository: WorkspaceScopedRepository, @InjectRepository(ApplicationEntity) private readonly applicationRepository: Repository, @InjectRepository(FieldMetadataEntity) private readonly fieldMetadataRepository: Repository, - @InjectRepository(ViewFilterGroupEntity) - private readonly viewFilterGroupRepository: Repository, - @InjectRepository(ViewEntity) - private readonly viewRepository: Repository, + @InjectWorkspaceScopedRepository(ViewFilterGroupEntity) + private readonly viewFilterGroupRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(ViewEntity) + private readonly viewRepository: WorkspaceScopedRepository, ) { super(); } @@ -38,8 +40,7 @@ export class WorkspaceFlatViewFilterMapCacheService extends WorkspaceCacheProvid async computeForCache(workspaceId: string): Promise { const [viewFilters, applications, fieldMetadatas, viewFilterGroups, views] = await Promise.all([ - this.viewFilterRepository.find({ - where: { workspaceId }, + this.viewFilterRepository.find(workspaceId, { withDeleted: true, }), this.applicationRepository.find({ @@ -52,13 +53,11 @@ export class WorkspaceFlatViewFilterMapCacheService extends WorkspaceCacheProvid select: ['id', 'universalIdentifier'], withDeleted: true, }), - this.viewFilterGroupRepository.find({ - where: { workspaceId }, + this.viewFilterGroupRepository.find(workspaceId, { select: ['id', 'universalIdentifier'], withDeleted: true, }), - this.viewRepository.find({ - where: { workspaceId }, + this.viewRepository.find(workspaceId, { select: ['id', 'universalIdentifier'], withDeleted: true, }), diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-view-group/services/workspace-flat-view-group-map-cache.service.ts b/packages/twenty-server/src/engine/metadata-modules/flat-view-group/services/workspace-flat-view-group-map-cache.service.ts index e122d83c39c..f18b855802f 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-view-group/services/workspace-flat-view-group-map-cache.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-view-group/services/workspace-flat-view-group-map-cache.service.ts @@ -11,6 +11,8 @@ import { FlatViewGroupMaps } from 'src/engine/metadata-modules/flat-view-group/t import { fromViewGroupEntityToFlatViewGroup } from 'src/engine/metadata-modules/flat-view-group/utils/from-view-group-entity-to-flat-view-group.util'; import { ViewGroupEntity } from 'src/engine/metadata-modules/view-group/entities/view-group.entity'; import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator'; import { createIdToUniversalIdentifierMap } from 'src/engine/workspace-cache/utils/create-id-to-universal-identifier-map.util'; import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/workspace-manager/workspace-migration/utils/add-flat-entity-to-flat-entity-maps-through-mutation-or-throw.util'; @@ -19,20 +21,19 @@ import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/ @WorkspaceCache('flatViewGroupMaps') export class WorkspaceFlatViewGroupMapCacheService extends WorkspaceCacheProvider { constructor( - @InjectRepository(ViewGroupEntity) - private readonly viewGroupRepository: Repository, + @InjectWorkspaceScopedRepository(ViewGroupEntity) + private readonly viewGroupRepository: WorkspaceScopedRepository, @InjectRepository(ApplicationEntity) private readonly applicationRepository: Repository, - @InjectRepository(ViewEntity) - private readonly viewRepository: Repository, + @InjectWorkspaceScopedRepository(ViewEntity) + private readonly viewRepository: WorkspaceScopedRepository, ) { super(); } async computeForCache(workspaceId: string): Promise { const [viewGroups, applications, views] = await Promise.all([ - this.viewGroupRepository.find({ - where: { workspaceId }, + this.viewGroupRepository.find(workspaceId, { withDeleted: true, }), this.applicationRepository.find({ @@ -40,8 +41,7 @@ export class WorkspaceFlatViewGroupMapCacheService extends WorkspaceCacheProvide select: ['id', 'universalIdentifier'], withDeleted: true, }), - this.viewRepository.find({ - where: { workspaceId }, + this.viewRepository.find(workspaceId, { select: ['id', 'universalIdentifier'], withDeleted: true, }), diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-view-sort/services/workspace-flat-view-sort-map-cache.service.ts b/packages/twenty-server/src/engine/metadata-modules/flat-view-sort/services/workspace-flat-view-sort-map-cache.service.ts index fef98eb5c6f..76ccbfc3ca2 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-view-sort/services/workspace-flat-view-sort-map-cache.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-view-sort/services/workspace-flat-view-sort-map-cache.service.ts @@ -5,6 +5,8 @@ import { Repository } from 'typeorm'; import { WorkspaceCacheProvider } from 'src/engine/workspace-cache/interfaces/workspace-cache-provider.service'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator'; import { FlatViewSortMaps } from 'src/engine/metadata-modules/flat-view-sort/types/flat-view-sort-maps.type'; import { ViewSortEntity } from 'src/engine/metadata-modules/view-sort/entities/view-sort.entity'; @@ -20,10 +22,10 @@ import { createIdToUniversalIdentifierMap } from 'src/engine/workspace-cache/uti @WorkspaceCache('flatViewSortMaps') export class WorkspaceFlatViewSortMapCacheService extends WorkspaceCacheProvider { constructor( - @InjectRepository(ViewSortEntity) - private readonly viewSortRepository: Repository, - @InjectRepository(ViewEntity) - private readonly viewRepository: Repository, + @InjectWorkspaceScopedRepository(ViewSortEntity) + private readonly viewSortRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(ViewEntity) + private readonly viewRepository: WorkspaceScopedRepository, @InjectRepository(ApplicationEntity) private readonly applicationRepository: Repository, @InjectRepository(FieldMetadataEntity) @@ -35,8 +37,7 @@ export class WorkspaceFlatViewSortMapCacheService extends WorkspaceCacheProvider async computeForCache(workspaceId: string): Promise { const [existingViewSorts, applications, views, fieldMetadatas] = await Promise.all([ - this.viewSortRepository.find({ - where: { workspaceId }, + this.viewSortRepository.find(workspaceId, { withDeleted: true, }), this.applicationRepository.find({ @@ -44,8 +45,7 @@ export class WorkspaceFlatViewSortMapCacheService extends WorkspaceCacheProvider select: ['id', 'universalIdentifier'], withDeleted: true, }), - this.viewRepository.find({ - where: { workspaceId }, + this.viewRepository.find(workspaceId, { select: ['id', 'universalIdentifier'], withDeleted: true, }), diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-view/flat-view.module.ts b/packages/twenty-server/src/engine/metadata-modules/flat-view/flat-view.module.ts index 81ab3862c59..c3ce0fef2b4 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-view/flat-view.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-view/flat-view.module.ts @@ -12,6 +12,7 @@ import { ViewFilterEntity } from 'src/engine/metadata-modules/view-filter/entiti import { ViewGroupEntity } from 'src/engine/metadata-modules/view-group/entities/view-group.entity'; import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity'; import { ViewSortEntity } from 'src/engine/metadata-modules/view-sort/entities/view-sort.entity'; +import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/provide-workspace-scoped-repository'; @Module({ imports: [ @@ -28,7 +29,16 @@ import { ViewSortEntity } from 'src/engine/metadata-modules/view-sort/entities/v ViewFilterGroupEntity, ]), ], - providers: [WorkspaceFlatViewMapCacheService], + providers: [ + WorkspaceFlatViewMapCacheService, + provideWorkspaceScopedRepository(ViewEntity), + provideWorkspaceScopedRepository(ViewFieldEntity), + provideWorkspaceScopedRepository(ViewFieldGroupEntity), + provideWorkspaceScopedRepository(ViewFilterEntity), + provideWorkspaceScopedRepository(ViewFilterGroupEntity), + provideWorkspaceScopedRepository(ViewGroupEntity), + provideWorkspaceScopedRepository(ViewSortEntity), + ], exports: [WorkspaceFlatViewMapCacheService], }) export class FlatViewModule {} diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-view/services/workspace-flat-view-map-cache.service.ts b/packages/twenty-server/src/engine/metadata-modules/flat-view/services/workspace-flat-view-map-cache.service.ts index 6893263aadd..da77c56f9ef 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-view/services/workspace-flat-view-map-cache.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-view/services/workspace-flat-view-map-cache.service.ts @@ -18,6 +18,8 @@ import { ViewFilterEntity } from 'src/engine/metadata-modules/view-filter/entiti import { ViewGroupEntity } from 'src/engine/metadata-modules/view-group/entities/view-group.entity'; import { ViewSortEntity } from 'src/engine/metadata-modules/view-sort/entities/view-sort.entity'; import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator'; import { createIdToUniversalIdentifierMap } from 'src/engine/workspace-cache/utils/create-id-to-universal-identifier-map.util'; import { regroupEntitiesByRelatedEntityId } from 'src/engine/workspace-cache/utils/regroup-entities-by-related-entity-id'; @@ -27,26 +29,26 @@ import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/ @WorkspaceCache('flatViewMaps') export class WorkspaceFlatViewMapCacheService extends WorkspaceCacheProvider { constructor( - @InjectRepository(ViewEntity) - private readonly viewRepository: Repository, + @InjectWorkspaceScopedRepository(ViewEntity) + private readonly viewRepository: WorkspaceScopedRepository, @InjectRepository(ApplicationEntity) private readonly applicationRepository: Repository, @InjectRepository(ObjectMetadataEntity) private readonly objectMetadataRepository: Repository, @InjectRepository(FieldMetadataEntity) private readonly fieldMetadataRepository: Repository, - @InjectRepository(ViewFieldEntity) - private readonly viewFieldRepository: Repository, - @InjectRepository(ViewFilterEntity) - private readonly viewFilterRepository: Repository, - @InjectRepository(ViewGroupEntity) - private readonly viewGroupRepository: Repository, - @InjectRepository(ViewFilterGroupEntity) - private readonly viewFilterGroupRepository: Repository, - @InjectRepository(ViewSortEntity) - private readonly viewSortRepository: Repository, - @InjectRepository(ViewFieldGroupEntity) - private readonly viewFieldGroupRepository: Repository, + @InjectWorkspaceScopedRepository(ViewFieldEntity) + private readonly viewFieldRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(ViewFilterEntity) + private readonly viewFilterRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(ViewGroupEntity) + private readonly viewGroupRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(ViewFilterGroupEntity) + private readonly viewFilterGroupRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(ViewSortEntity) + private readonly viewSortRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(ViewFieldGroupEntity) + private readonly viewFieldGroupRepository: WorkspaceScopedRepository, ) { super(); } @@ -64,8 +66,7 @@ export class WorkspaceFlatViewMapCacheService extends WorkspaceCacheProvider { constructor( - @InjectRepository(WebhookEntity) - private readonly webhookRepository: Repository, + @InjectWorkspaceScopedRepository(WebhookEntity) + private readonly webhookRepository: WorkspaceScopedRepository, @InjectRepository(ApplicationEntity) private readonly applicationRepository: Repository, ) { @@ -28,8 +30,8 @@ export class WorkspaceFlatWebhookMapCacheService extends WorkspaceCacheProvider< async computeForCache(workspaceId: string): Promise { const [webhooks, applications] = await Promise.all([ - this.webhookRepository.find({ - where: { workspaceId, deletedAt: IsNull() }, + this.webhookRepository.find(workspaceId, { + where: { deletedAt: IsNull() }, }), this.applicationRepository.find({ where: { workspaceId }, diff --git a/packages/twenty-server/src/engine/metadata-modules/permissions/__tests__/permissions.service.spec.ts b/packages/twenty-server/src/engine/metadata-modules/permissions/__tests__/permissions.service.spec.ts index 2b5e91f76e2..24df69949d7 100644 --- a/packages/twenty-server/src/engine/metadata-modules/permissions/__tests__/permissions.service.spec.ts +++ b/packages/twenty-server/src/engine/metadata-modules/permissions/__tests__/permissions.service.spec.ts @@ -11,6 +11,7 @@ import { ApplicationEntity } from 'src/engine/core-modules/application/applicati import { PermissionsService } from 'src/engine/metadata-modules/permissions/permissions.service'; import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role.service'; +import { getWorkspaceScopedRepositoryToken } from 'src/engine/twenty-orm/workspace-scoped-repository/get-workspace-scoped-repository-token.util'; import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; describe('PermissionsService', () => { @@ -21,7 +22,7 @@ describe('PermissionsService', () => { providers: [ PermissionsService, { - provide: getRepositoryToken(RoleEntity), + provide: getWorkspaceScopedRepositoryToken(RoleEntity), useValue: {}, }, { diff --git a/packages/twenty-server/src/engine/metadata-modules/permissions/permissions.module.ts b/packages/twenty-server/src/engine/metadata-modules/permissions/permissions.module.ts index 975b00d6cdc..4241f20c1b2 100644 --- a/packages/twenty-server/src/engine/metadata-modules/permissions/permissions.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/permissions/permissions.module.ts @@ -32,6 +32,8 @@ import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache ApiKeyRoleService, PermissionsService, provideWorkspaceScopedRepository(ApiKeyEntity), + provideWorkspaceScopedRepository(RoleEntity), + provideWorkspaceScopedRepository(RoleTargetEntity), ], exports: [PermissionsService, ApiKeyRoleService], }) diff --git a/packages/twenty-server/src/engine/metadata-modules/permissions/permissions.service.ts b/packages/twenty-server/src/engine/metadata-modules/permissions/permissions.service.ts index 05b1154eec4..14b8cb9c0e6 100644 --- a/packages/twenty-server/src/engine/metadata-modules/permissions/permissions.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/permissions/permissions.service.ts @@ -25,6 +25,8 @@ import { type UserWorkspacePermissions } from 'src/engine/metadata-modules/permi import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role.service'; import { type RolePermissionConfig } from 'src/engine/twenty-orm/types/role-permission-config'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; @Injectable() @@ -33,8 +35,8 @@ export class PermissionsService { private readonly userRoleService: UserRoleService, private readonly workspaceCacheService: WorkspaceCacheService, private readonly apiKeyRoleService: ApiKeyRoleService, - @InjectRepository(RoleEntity) - private readonly roleRepository: Repository, + @InjectWorkspaceScopedRepository(RoleEntity) + private readonly roleRepository: WorkspaceScopedRepository, @InjectRepository(ApplicationEntity) private readonly applicationRepository: Repository, ) {} @@ -149,8 +151,8 @@ export class PermissionsService { workspaceId, ); - const role = await this.roleRepository.findOne({ - where: { id: roleId, workspaceId }, + const role = await this.roleRepository.findOne(workspaceId, { + where: { id: roleId }, relations: [ 'rolePermissionFlags', 'rolePermissionFlags.permissionFlag', @@ -205,8 +207,8 @@ export class PermissionsService { const applicationRoleId = application.defaultRoleId; - const role = await this.roleRepository.findOne({ - where: { id: applicationRoleId, workspaceId }, + const role = await this.roleRepository.findOne(workspaceId, { + where: { id: applicationRoleId }, relations: [ 'rolePermissionFlags', 'rolePermissionFlags.permissionFlag', @@ -289,8 +291,8 @@ export class PermissionsService { throw new Error('No role IDs provided'); } - const roles = await this.roleRepository.find({ - where: { id: In(roleIds), workspaceId }, + const roles = await this.roleRepository.find(workspaceId, { + where: { id: In(roleIds) }, relations, }); diff --git a/packages/twenty-server/src/engine/metadata-modules/role-target/role-target.module.ts b/packages/twenty-server/src/engine/metadata-modules/role-target/role-target.module.ts index 11f972ef82c..48092ef2cc5 100644 --- a/packages/twenty-server/src/engine/metadata-modules/role-target/role-target.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/role-target/role-target.module.ts @@ -6,6 +6,7 @@ import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata import { RoleTargetEntity } from 'src/engine/metadata-modules/role-target/role-target.entity'; import { WorkspaceApiKeyRoleMapCacheService } from 'src/engine/metadata-modules/role-target/services/workspace-api-key-role-map-cache.service'; import { WorkspaceUserWorkspaceRoleMapCacheService } from 'src/engine/metadata-modules/role-target/services/workspace-user-workspace-role-map-cache.service'; +import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/provide-workspace-scoped-repository'; import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration.module'; import { RoleTargetService } from './services/role-target.service'; @@ -21,6 +22,7 @@ import { RoleTargetService } from './services/role-target.service'; RoleTargetService, WorkspaceUserWorkspaceRoleMapCacheService, WorkspaceApiKeyRoleMapCacheService, + provideWorkspaceScopedRepository(RoleTargetEntity), ], exports: [RoleTargetService], }) diff --git a/packages/twenty-server/src/engine/metadata-modules/role-target/services/workspace-api-key-role-map-cache.service.ts b/packages/twenty-server/src/engine/metadata-modules/role-target/services/workspace-api-key-role-map-cache.service.ts index 035f4f1e7d2..072f593f32d 100644 --- a/packages/twenty-server/src/engine/metadata-modules/role-target/services/workspace-api-key-role-map-cache.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/role-target/services/workspace-api-key-role-map-cache.service.ts @@ -1,11 +1,12 @@ import { Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; -import { IsNull, Not, Repository } from 'typeorm'; +import { IsNull, Not } from 'typeorm'; import { WorkspaceCacheProvider } from 'src/engine/workspace-cache/interfaces/workspace-cache-provider.service'; import { RoleTargetEntity } from 'src/engine/metadata-modules/role-target/role-target.entity'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator'; @Injectable() @@ -14,16 +15,15 @@ export class WorkspaceApiKeyRoleMapCacheService extends WorkspaceCacheProvider< Record > { constructor( - @InjectRepository(RoleTargetEntity) - private readonly roleTargetRepository: Repository, + @InjectWorkspaceScopedRepository(RoleTargetEntity) + private readonly roleTargetRepository: WorkspaceScopedRepository, ) { super(); } async computeForCache(workspaceId: string): Promise> { - const roleTargetsMap = await this.roleTargetRepository.find({ + const roleTargetsMap = await this.roleTargetRepository.find(workspaceId, { where: { - workspaceId, apiKeyId: Not(IsNull()), }, }); diff --git a/packages/twenty-server/src/engine/metadata-modules/role-target/services/workspace-user-workspace-role-map-cache.service.ts b/packages/twenty-server/src/engine/metadata-modules/role-target/services/workspace-user-workspace-role-map-cache.service.ts index da07c8cb7f8..a972fd928f6 100644 --- a/packages/twenty-server/src/engine/metadata-modules/role-target/services/workspace-user-workspace-role-map-cache.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/role-target/services/workspace-user-workspace-role-map-cache.service.ts @@ -1,29 +1,29 @@ import { Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; import { isDefined } from 'twenty-shared/utils'; -import { IsNull, Not, Repository } from 'typeorm'; +import { IsNull, Not } from 'typeorm'; import { WorkspaceCacheProvider } from 'src/engine/workspace-cache/interfaces/workspace-cache-provider.service'; import { RoleTargetEntity } from 'src/engine/metadata-modules/role-target/role-target.entity'; import { UserWorkspaceRoleMap } from 'src/engine/metadata-modules/role-target/types/user-workspace-role-map'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator'; @Injectable() @WorkspaceCache('userWorkspaceRoleMap') export class WorkspaceUserWorkspaceRoleMapCacheService extends WorkspaceCacheProvider { constructor( - @InjectRepository(RoleTargetEntity) - private readonly roleTargetRepository: Repository, + @InjectWorkspaceScopedRepository(RoleTargetEntity) + private readonly roleTargetRepository: WorkspaceScopedRepository, ) { super(); } async computeForCache(workspaceId: string): Promise { - const roleTargetsMap = await this.roleTargetRepository.find({ + const roleTargetsMap = await this.roleTargetRepository.find(workspaceId, { where: { - workspaceId, userWorkspaceId: Not(IsNull()), }, }); diff --git a/packages/twenty-server/src/engine/metadata-modules/role-validation/role-validation.module.ts b/packages/twenty-server/src/engine/metadata-modules/role-validation/role-validation.module.ts index 53bf67aef83..2b83e2054c9 100644 --- a/packages/twenty-server/src/engine/metadata-modules/role-validation/role-validation.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/role-validation/role-validation.module.ts @@ -3,10 +3,14 @@ import { TypeOrmModule } from '@nestjs/typeorm'; import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; import { RoleValidationService } from 'src/engine/metadata-modules/role-validation/services/role-validation.service'; +import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/provide-workspace-scoped-repository'; @Module({ imports: [TypeOrmModule.forFeature([RoleEntity])], - providers: [RoleValidationService], + providers: [ + RoleValidationService, + provideWorkspaceScopedRepository(RoleEntity), + ], exports: [RoleValidationService], }) export class RoleValidationModule {} diff --git a/packages/twenty-server/src/engine/metadata-modules/role-validation/services/role-validation.service.ts b/packages/twenty-server/src/engine/metadata-modules/role-validation/services/role-validation.service.ts index a9d11b7031b..e32cf4bfd60 100644 --- a/packages/twenty-server/src/engine/metadata-modules/role-validation/services/role-validation.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/role-validation/services/role-validation.service.ts @@ -1,7 +1,4 @@ import { Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; - -import { Repository } from 'typeorm'; import { PermissionsException, @@ -9,22 +6,23 @@ import { PermissionsExceptionMessage, } from 'src/engine/metadata-modules/permissions/permissions.exception'; import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; @Injectable() export class RoleValidationService { constructor( - @InjectRepository(RoleEntity) - private readonly roleRepository: Repository, + @InjectWorkspaceScopedRepository(RoleEntity) + private readonly roleRepository: WorkspaceScopedRepository, ) {} async validateRoleAssignableToUsersOrThrow( roleId: string, workspaceId: string, ): Promise { - const role = await this.roleRepository.findOne({ + const role = await this.roleRepository.findOne(workspaceId, { where: { id: roleId, - workspaceId, }, }); diff --git a/packages/twenty-server/src/engine/metadata-modules/role/role.module.ts b/packages/twenty-server/src/engine/metadata-modules/role/role.module.ts index eaed1e34a86..ee931545bdb 100644 --- a/packages/twenty-server/src/engine/metadata-modules/role/role.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/role/role.module.ts @@ -28,6 +28,7 @@ import { RowLevelPermissionPredicateGroupEntity } from 'src/engine/metadata-modu import { RowLevelPermissionPredicateEntity } from 'src/engine/metadata-modules/row-level-permission-predicate/entities/row-level-permission-predicate.entity'; import { RowLevelPermissionModule } from 'src/engine/metadata-modules/row-level-permission-predicate/row-level-permission.module'; import { UserRoleModule } from 'src/engine/metadata-modules/user-role/user-role.module'; +import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/provide-workspace-scoped-repository'; import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module'; import { WorkspaceMigrationGraphqlApiExceptionInterceptor } from 'src/engine/workspace-manager/workspace-migration/interceptors/workspace-migration-graphql-api-exception.interceptor'; import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration.module'; @@ -69,6 +70,12 @@ import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace WorkspaceFlatRoleTargetMapCacheService, WorkspaceMigrationGraphqlApiExceptionInterceptor, WorkspaceRolesPermissionsCacheService, + provideWorkspaceScopedRepository(RoleEntity), + provideWorkspaceScopedRepository(RoleTargetEntity), + provideWorkspaceScopedRepository(ObjectPermissionEntity), + provideWorkspaceScopedRepository(FieldPermissionEntity), + provideWorkspaceScopedRepository(RowLevelPermissionPredicateEntity), + provideWorkspaceScopedRepository(RowLevelPermissionPredicateGroupEntity), ], exports: [ RoleService, diff --git a/packages/twenty-server/src/engine/metadata-modules/role/role.service.ts b/packages/twenty-server/src/engine/metadata-modules/role/role.service.ts index e86a2481d09..d7058900a23 100644 --- a/packages/twenty-server/src/engine/metadata-modules/role/role.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/role/role.service.ts @@ -36,6 +36,8 @@ import { type UpdateRoleInput } from 'src/engine/metadata-modules/role/dtos/upda import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; import { fromFlatRoleToRoleDto } from 'src/engine/metadata-modules/role/utils/fromFlatRoleToRoleDto.util'; import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role.service'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager/workspace-migration/exceptions/workspace-migration-builder-exception'; import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service'; @@ -46,8 +48,8 @@ export class RoleService { private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, @InjectRepository(WorkspaceEntity) private readonly workspaceRepository: Repository, - @InjectRepository(RoleEntity) - private readonly roleRepository: Repository, + @InjectWorkspaceScopedRepository(RoleEntity) + private readonly roleRepository: WorkspaceScopedRepository, private readonly userRoleService: UserRoleService, private readonly applicationService: ApplicationService, private readonly apiKeyRoleService: ApiKeyRoleService, @@ -55,10 +57,7 @@ export class RoleService { ) {} public async getWorkspaceRoles(workspaceId: string): Promise { - return this.roleRepository.find({ - where: { - workspaceId, - }, + return this.roleRepository.find(workspaceId, { relations: { roleTargets: true, rolePermissionFlags: { @@ -74,10 +73,9 @@ export class RoleService { id: string, workspaceId: string, ): Promise { - return this.roleRepository.findOne({ + return this.roleRepository.findOne(workspaceId, { where: { id, - workspaceId, }, relations: { roleTargets: true, diff --git a/packages/twenty-server/src/engine/metadata-modules/role/services/__tests__/workspace-roles-permissions-cache.service.spec.ts b/packages/twenty-server/src/engine/metadata-modules/role/services/__tests__/workspace-roles-permissions-cache.service.spec.ts index 08a6a049361..8ada548fb5b 100644 --- a/packages/twenty-server/src/engine/metadata-modules/role/services/__tests__/workspace-roles-permissions-cache.service.spec.ts +++ b/packages/twenty-server/src/engine/metadata-modules/role/services/__tests__/workspace-roles-permissions-cache.service.spec.ts @@ -16,6 +16,8 @@ import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; import { WorkspaceRolesPermissionsCacheService } from 'src/engine/metadata-modules/role/services/workspace-roles-permissions-cache.service'; import { RowLevelPermissionPredicateGroupEntity } from 'src/engine/metadata-modules/row-level-permission-predicate/entities/row-level-permission-predicate-group.entity'; import { RowLevelPermissionPredicateEntity } from 'src/engine/metadata-modules/row-level-permission-predicate/entities/row-level-permission-predicate.entity'; +import { getWorkspaceScopedRepositoryToken } from 'src/engine/twenty-orm/workspace-scoped-repository/get-workspace-scoped-repository-token.util'; +import { type WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; const WORKSPACE_ID = '20202020-0000-4000-8000-000000000000'; const ROLE_ID = '11111111-1111-4111-8111-111111111111'; @@ -52,12 +54,14 @@ const createBaseRole = ( describe('WorkspaceRolesPermissionsCacheService', () => { let service: WorkspaceRolesPermissionsCacheService; - let roleRepository: jest.Mocked, 'find'>>; + let roleRepository: jest.Mocked< + Pick, 'find'> + >; let objectMetadataRepository: jest.Mocked< Pick, 'find'> >; let objectPermissionRepository: jest.Mocked< - Pick, 'find'> + Pick, 'find'> >; let rolePermissionFlagRepository: jest.Mocked< Pick, 'find'> @@ -118,11 +122,11 @@ describe('WorkspaceRolesPermissionsCacheService', () => { useValue: objectMetadataRepository, }, { - provide: getRepositoryToken(RoleEntity), + provide: getWorkspaceScopedRepositoryToken(RoleEntity), useValue: roleRepository, }, { - provide: getRepositoryToken(ObjectPermissionEntity), + provide: getWorkspaceScopedRepositoryToken(ObjectPermissionEntity), useValue: objectPermissionRepository, }, { @@ -130,15 +134,19 @@ describe('WorkspaceRolesPermissionsCacheService', () => { useValue: rolePermissionFlagRepository, }, { - provide: getRepositoryToken(FieldPermissionEntity), + provide: getWorkspaceScopedRepositoryToken(FieldPermissionEntity), useValue: fieldPermissionRepository, }, { - provide: getRepositoryToken(RowLevelPermissionPredicateEntity), + provide: getWorkspaceScopedRepositoryToken( + RowLevelPermissionPredicateEntity, + ), useValue: rowLevelPermissionPredicateRepository, }, { - provide: getRepositoryToken(RowLevelPermissionPredicateGroupEntity), + provide: getWorkspaceScopedRepositoryToken( + RowLevelPermissionPredicateGroupEntity, + ), useValue: rowLevelPermissionPredicateGroupRepository, }, ], diff --git a/packages/twenty-server/src/engine/metadata-modules/role/services/workspace-flat-role-map-cache.service.ts b/packages/twenty-server/src/engine/metadata-modules/role/services/workspace-flat-role-map-cache.service.ts index 054190ffb68..5dfec227bb4 100644 --- a/packages/twenty-server/src/engine/metadata-modules/role/services/workspace-flat-role-map-cache.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/role/services/workspace-flat-role-map-cache.service.ts @@ -17,6 +17,8 @@ import { RoleTargetEntity } from 'src/engine/metadata-modules/role-target/role-t import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; import { RowLevelPermissionPredicateGroupEntity } from 'src/engine/metadata-modules/row-level-permission-predicate/entities/row-level-permission-predicate-group.entity'; import { RowLevelPermissionPredicateEntity } from 'src/engine/metadata-modules/row-level-permission-predicate/entities/row-level-permission-predicate.entity'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator'; import { createIdToUniversalIdentifierMap } from 'src/engine/workspace-cache/utils/create-id-to-universal-identifier-map.util'; import { regroupEntitiesByRelatedEntityId } from 'src/engine/workspace-cache/utils/regroup-entities-by-related-entity-id'; @@ -28,22 +30,22 @@ export class WorkspaceFlatRoleMapCacheService extends WorkspaceCacheProvider< FlatEntityMaps > { constructor( - @InjectRepository(RoleEntity) - private readonly roleRepository: Repository, + @InjectWorkspaceScopedRepository(RoleEntity) + private readonly roleRepository: WorkspaceScopedRepository, @InjectRepository(ApplicationEntity) private readonly applicationRepository: Repository, - @InjectRepository(RoleTargetEntity) - private readonly roleTargetRepository: Repository, - @InjectRepository(ObjectPermissionEntity) - private readonly objectPermissionRepository: Repository, + @InjectWorkspaceScopedRepository(RoleTargetEntity) + private readonly roleTargetRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(ObjectPermissionEntity) + private readonly objectPermissionRepository: WorkspaceScopedRepository, @InjectRepository(RolePermissionFlagEntity) private readonly rolePermissionFlagRepository: Repository, - @InjectRepository(FieldPermissionEntity) - private readonly fieldPermissionRepository: Repository, - @InjectRepository(RowLevelPermissionPredicateEntity) - private readonly rowLevelPermissionPredicateRepository: Repository, - @InjectRepository(RowLevelPermissionPredicateGroupEntity) - private readonly rowLevelPermissionPredicateGroupRepository: Repository, + @InjectWorkspaceScopedRepository(FieldPermissionEntity) + private readonly fieldPermissionRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(RowLevelPermissionPredicateEntity) + private readonly rowLevelPermissionPredicateRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(RowLevelPermissionPredicateGroupEntity) + private readonly rowLevelPermissionPredicateGroupRepository: WorkspaceScopedRepository, ) { super(); } @@ -61,8 +63,7 @@ export class WorkspaceFlatRoleMapCacheService extends WorkspaceCacheProvider< rowLevelPermissionPredicates, rowLevelPermissionPredicateGroups, ] = await Promise.all([ - this.roleRepository.find({ - where: { workspaceId }, + this.roleRepository.find(workspaceId, { withDeleted: true, }), this.applicationRepository.find({ @@ -70,13 +71,11 @@ export class WorkspaceFlatRoleMapCacheService extends WorkspaceCacheProvider< select: ['id', 'universalIdentifier'], withDeleted: true, }), - this.roleTargetRepository.find({ - where: { workspaceId }, + this.roleTargetRepository.find(workspaceId, { select: ['id', 'universalIdentifier', 'roleId'], withDeleted: true, }), - this.objectPermissionRepository.find({ - where: { workspaceId }, + this.objectPermissionRepository.find(workspaceId, { select: ['id', 'universalIdentifier', 'roleId'], withDeleted: true, }), @@ -85,18 +84,15 @@ export class WorkspaceFlatRoleMapCacheService extends WorkspaceCacheProvider< select: ['id', 'universalIdentifier', 'roleId'], withDeleted: true, }), - this.fieldPermissionRepository.find({ - where: { workspaceId }, + this.fieldPermissionRepository.find(workspaceId, { select: ['id', 'universalIdentifier', 'roleId'], withDeleted: true, }), - this.rowLevelPermissionPredicateRepository.find({ - where: { workspaceId }, + this.rowLevelPermissionPredicateRepository.find(workspaceId, { select: ['id', 'universalIdentifier', 'roleId'], withDeleted: true, }), - this.rowLevelPermissionPredicateGroupRepository.find({ - where: { workspaceId }, + this.rowLevelPermissionPredicateGroupRepository.find(workspaceId, { select: ['id', 'universalIdentifier', 'roleId'], withDeleted: true, }), diff --git a/packages/twenty-server/src/engine/metadata-modules/role/services/workspace-roles-permissions-cache.service.ts b/packages/twenty-server/src/engine/metadata-modules/role/services/workspace-roles-permissions-cache.service.ts index 08b9c94457f..582bbfad28b 100644 --- a/packages/twenty-server/src/engine/metadata-modules/role/services/workspace-roles-permissions-cache.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/role/services/workspace-roles-permissions-cache.service.ts @@ -23,6 +23,8 @@ import { RolePermissionFlagEntity } from 'src/engine/metadata-modules/role-permi import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; import { RowLevelPermissionPredicateGroupEntity } from 'src/engine/metadata-modules/row-level-permission-predicate/entities/row-level-permission-predicate-group.entity'; import { RowLevelPermissionPredicateEntity } from 'src/engine/metadata-modules/row-level-permission-predicate/entities/row-level-permission-predicate.entity'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator'; import { regroupEntitiesByRelatedEntityId } from 'src/engine/workspace-cache/utils/regroup-entities-by-related-entity-id'; @@ -40,18 +42,18 @@ export class WorkspaceRolesPermissionsCacheService extends WorkspaceCacheProvide constructor( @InjectRepository(ObjectMetadataEntity) private readonly objectMetadataRepository: Repository, - @InjectRepository(RoleEntity) - private readonly roleRepository: Repository, - @InjectRepository(ObjectPermissionEntity) - private readonly objectPermissionRepository: Repository, + @InjectWorkspaceScopedRepository(RoleEntity) + private readonly roleRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(ObjectPermissionEntity) + private readonly objectPermissionRepository: WorkspaceScopedRepository, @InjectRepository(RolePermissionFlagEntity) private readonly rolePermissionFlagRepository: Repository, - @InjectRepository(FieldPermissionEntity) - private readonly fieldPermissionRepository: Repository, - @InjectRepository(RowLevelPermissionPredicateEntity) - private readonly rowLevelPermissionPredicateRepository: Repository, - @InjectRepository(RowLevelPermissionPredicateGroupEntity) - private readonly rowLevelPermissionPredicateGroupRepository: Repository, + @InjectWorkspaceScopedRepository(FieldPermissionEntity) + private readonly fieldPermissionRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(RowLevelPermissionPredicateEntity) + private readonly rowLevelPermissionPredicateRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(RowLevelPermissionPredicateGroupEntity) + private readonly rowLevelPermissionPredicateGroupRepository: WorkspaceScopedRepository, ) { super(); } @@ -68,24 +70,18 @@ export class WorkspaceRolesPermissionsCacheService extends WorkspaceCacheProvide rowLevelPermissionPredicateGroups, workspaceObjectMetadataCollection, ] = await Promise.all([ - this.roleRepository.find({ - where: { workspaceId }, - }), - this.objectPermissionRepository.find({ - where: { workspaceId }, - }), + this.roleRepository.find(workspaceId), + this.objectPermissionRepository.find(workspaceId), this.rolePermissionFlagRepository.find({ where: { workspaceId }, relations: ['permissionFlag'], }), - this.fieldPermissionRepository.find({ - where: { workspaceId }, + this.fieldPermissionRepository.find(workspaceId), + this.rowLevelPermissionPredicateRepository.find(workspaceId, { + where: { deletedAt: IsNull() }, }), - this.rowLevelPermissionPredicateRepository.find({ - where: { workspaceId, deletedAt: IsNull() }, - }), - this.rowLevelPermissionPredicateGroupRepository.find({ - where: { workspaceId, deletedAt: IsNull() }, + this.rowLevelPermissionPredicateGroupRepository.find(workspaceId, { + where: { deletedAt: IsNull() }, }), this.getWorkspaceObjectMetadataCollection(workspaceId), ]); diff --git a/packages/twenty-server/src/engine/metadata-modules/row-level-permission-predicate/row-level-permission.module.ts b/packages/twenty-server/src/engine/metadata-modules/row-level-permission-predicate/row-level-permission.module.ts index 828cb74999b..abeb8ccfcd1 100644 --- a/packages/twenty-server/src/engine/metadata-modules/row-level-permission-predicate/row-level-permission.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/row-level-permission-predicate/row-level-permission.module.ts @@ -11,6 +11,7 @@ import { RowLevelPermissionPredicateGroupEntity } from 'src/engine/metadata-modu import { RowLevelPermissionPredicateEntity } from 'src/engine/metadata-modules/row-level-permission-predicate/entities/row-level-permission-predicate.entity'; import { RowLevelPermissionPredicateGroupService } from 'src/engine/metadata-modules/row-level-permission-predicate/services/row-level-permission-predicate-group.service'; import { RowLevelPermissionPredicateService } from 'src/engine/metadata-modules/row-level-permission-predicate/services/row-level-permission-predicate.service'; +import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/provide-workspace-scoped-repository'; import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module'; import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration.module'; @@ -30,6 +31,7 @@ import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace providers: [ RowLevelPermissionPredicateService, RowLevelPermissionPredicateGroupService, + provideWorkspaceScopedRepository(RowLevelPermissionPredicateGroupEntity), ], exports: [ RowLevelPermissionPredicateService, diff --git a/packages/twenty-server/src/engine/metadata-modules/row-level-permission-predicate/services/row-level-permission-predicate-group.service.ts b/packages/twenty-server/src/engine/metadata-modules/row-level-permission-predicate/services/row-level-permission-predicate-group.service.ts index 96293405344..a8a633695f4 100644 --- a/packages/twenty-server/src/engine/metadata-modules/row-level-permission-predicate/services/row-level-permission-predicate-group.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/row-level-permission-predicate/services/row-level-permission-predicate-group.service.ts @@ -1,10 +1,8 @@ /* @license Enterprise */ import { Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; import { isDefined } from 'twenty-shared/utils'; -import { Repository } from 'typeorm'; import { BillingEntitlementKey } from 'src/engine/core-modules/billing/enums/billing-entitlement-key.enum'; import { BillingService } from 'src/engine/core-modules/billing/services/billing.service'; @@ -14,6 +12,8 @@ import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/ import { fromFlatRowLevelPermissionPredicateGroupToDto } from 'src/engine/metadata-modules/flat-row-level-permission-predicate/utils/from-flat-row-level-permission-predicate-group-to-dto.util'; import { RowLevelPermissionPredicateGroupDTO } from 'src/engine/metadata-modules/row-level-permission-predicate/dtos/row-level-permission-predicate-group.dto'; import { RowLevelPermissionPredicateGroupEntity } from 'src/engine/metadata-modules/row-level-permission-predicate/entities/row-level-permission-predicate-group.entity'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; @Injectable() @@ -22,8 +22,8 @@ export class RowLevelPermissionPredicateGroupService { private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, private readonly workspaceCacheService: WorkspaceCacheService, private readonly billingService: BillingService, - @InjectRepository(RowLevelPermissionPredicateGroupEntity) - private readonly rowLevelPermissionPredicateGroupRepository: Repository, + @InjectWorkspaceScopedRepository(RowLevelPermissionPredicateGroupEntity) + private readonly rowLevelPermissionPredicateGroupRepository: WorkspaceScopedRepository, private readonly enterprisePlanService: EnterprisePlanService, ) {} @@ -122,9 +122,10 @@ export class RowLevelPermissionPredicateGroupService { } public async deleteAllRowLevelPermissionPredicateGroups(workspaceId: string) { - await this.rowLevelPermissionPredicateGroupRepository.delete({ + await this.rowLevelPermissionPredicateGroupRepository.delete( workspaceId, - }); + {}, + ); await this.workspaceCacheService.invalidateAndRecompute(workspaceId, [ 'rolesPermissions', diff --git a/packages/twenty-server/src/engine/metadata-modules/user-role/user-role.module.ts b/packages/twenty-server/src/engine/metadata-modules/user-role/user-role.module.ts index f3b8e0ee151..4f61e0bbdea 100644 --- a/packages/twenty-server/src/engine/metadata-modules/user-role/user-role.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/user-role/user-role.module.ts @@ -6,6 +6,7 @@ import { RoleTargetEntity } from 'src/engine/metadata-modules/role-target/role-t import { RoleTargetModule } from 'src/engine/metadata-modules/role-target/role-target.module'; import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role.service'; +import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/provide-workspace-scoped-repository'; import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module'; @Module({ @@ -15,7 +16,10 @@ import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache WorkspaceCacheModule, RoleTargetModule, ], - providers: [UserRoleService], + providers: [ + UserRoleService, + provideWorkspaceScopedRepository(RoleTargetEntity), + ], exports: [UserRoleService], }) export class UserRoleModule {} diff --git a/packages/twenty-server/src/engine/metadata-modules/user-role/user-role.service.ts b/packages/twenty-server/src/engine/metadata-modules/user-role/user-role.service.ts index 319b9808d01..54e09fba7e9 100644 --- a/packages/twenty-server/src/engine/metadata-modules/user-role/user-role.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/user-role/user-role.service.ts @@ -15,14 +15,16 @@ import { RoleTargetService } from 'src/engine/metadata-modules/role-target/servi import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; import { buildSystemAuthContext } from 'src/engine/twenty-orm/utils/build-system-auth-context.util'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; import { STANDARD_ROLE } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-role.constant'; import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; export class UserRoleService { constructor( - @InjectRepository(RoleTargetEntity) - private readonly roleTargetRepository: Repository, + @InjectWorkspaceScopedRepository(RoleTargetEntity) + private readonly roleTargetRepository: WorkspaceScopedRepository, @InjectRepository(UserWorkspaceEntity) private readonly userWorkspaceRepository: Repository, private readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager, @@ -101,10 +103,9 @@ export class UserRoleService { return new Map(); } - const allRoleTargets = await this.roleTargetRepository.find({ + const allRoleTargets = await this.roleTargetRepository.find(workspaceId, { where: { userWorkspaceId: In(userWorkspaceIds), - workspaceId, }, relations: { role: { diff --git a/packages/twenty-server/src/engine/metadata-modules/view-field-group/services/fields-widget-upsert.service.ts b/packages/twenty-server/src/engine/metadata-modules/view-field-group/services/fields-widget-upsert.service.ts index 79970eded43..ed3741bdd44 100644 --- a/packages/twenty-server/src/engine/metadata-modules/view-field-group/services/fields-widget-upsert.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/view-field-group/services/fields-widget-upsert.service.ts @@ -1,12 +1,11 @@ import { Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; import { t } from '@lingui/core/macro'; import { isDefined, isFieldMetadataEligibleForFieldsWidget, } from 'twenty-shared/utils'; -import { IsNull, Repository } from 'typeorm'; +import { IsNull } from 'typeorm'; import { v4 } from 'uuid'; import { ApplicationService } from 'src/engine/core-modules/application/application.service'; @@ -36,6 +35,8 @@ import { ViewFieldGroupExceptionCode, } from 'src/engine/metadata-modules/view-field-group/exceptions/view-field-group.exception'; import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager/workspace-migration/exceptions/workspace-migration-builder-exception'; import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service'; @@ -45,8 +46,8 @@ export class FieldsWidgetUpsertService { private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService, private readonly workspaceManyOrAllFlatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, private readonly applicationService: ApplicationService, - @InjectRepository(ViewEntity) - private readonly viewRepository: Repository, + @InjectWorkspaceScopedRepository(ViewEntity) + private readonly viewRepository: WorkspaceScopedRepository, ) {} async upsertFieldsWidget({ @@ -181,8 +182,8 @@ export class FieldsWidgetUpsertService { }); } - const view = await this.viewRepository.findOne({ - where: { id: viewId, workspaceId, deletedAt: IsNull() }, + const view = await this.viewRepository.findOne(workspaceId, { + where: { id: viewId, deletedAt: IsNull() }, }); if (!isDefined(view)) { diff --git a/packages/twenty-server/src/engine/metadata-modules/view-field-group/view-field-group.module.ts b/packages/twenty-server/src/engine/metadata-modules/view-field-group/view-field-group.module.ts index f3eb6ac7ed2..02db9440630 100644 --- a/packages/twenty-server/src/engine/metadata-modules/view-field-group/view-field-group.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/view-field-group/view-field-group.module.ts @@ -9,6 +9,7 @@ import { ViewFieldGroupResolver } from 'src/engine/metadata-modules/view-field-g import { FieldsWidgetUpsertService } from 'src/engine/metadata-modules/view-field-group/services/fields-widget-upsert.service'; import { ViewFieldGroupService } from 'src/engine/metadata-modules/view-field-group/services/view-field-group.service'; import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity'; +import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/provide-workspace-scoped-repository'; import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/workspace-cache-storage.module'; import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration.module'; @@ -25,6 +26,7 @@ import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace ViewFieldGroupResolver, ViewFieldGroupService, FieldsWidgetUpsertService, + provideWorkspaceScopedRepository(ViewEntity), ], exports: [ViewFieldGroupService], }) diff --git a/packages/twenty-server/src/engine/metadata-modules/view-filter-group/services/tests/view-filter-group.service.spec.ts b/packages/twenty-server/src/engine/metadata-modules/view-filter-group/services/tests/view-filter-group.service.spec.ts index 04b1f71de1a..24d65675f61 100644 --- a/packages/twenty-server/src/engine/metadata-modules/view-filter-group/services/tests/view-filter-group.service.spec.ts +++ b/packages/twenty-server/src/engine/metadata-modules/view-filter-group/services/tests/view-filter-group.service.spec.ts @@ -1,18 +1,18 @@ import { Test, type TestingModule } from '@nestjs/testing'; -import { getRepositoryToken } from '@nestjs/typeorm'; -import { type Repository } from 'typeorm'; import { ViewFilterGroupLogicalOperator } from 'twenty-shared/types'; import { ApplicationService } from 'src/engine/core-modules/application/application.service'; import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; import { ViewFilterGroupEntity } from 'src/engine/metadata-modules/view-filter-group/entities/view-filter-group.entity'; import { ViewFilterGroupService } from 'src/engine/metadata-modules/view-filter-group/services/view-filter-group.service'; +import { getWorkspaceScopedRepositoryToken } from 'src/engine/twenty-orm/workspace-scoped-repository/get-workspace-scoped-repository-token.util'; +import { type WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service'; describe('ViewFilterGroupService', () => { let viewFilterGroupService: ViewFilterGroupService; - let viewFilterGroupRepository: Repository; + let viewFilterGroupRepository: WorkspaceScopedRepository; const mockViewFilterGroup = { id: 'view-filter-group-id', @@ -30,13 +30,11 @@ describe('ViewFilterGroupService', () => { providers: [ ViewFilterGroupService, { - provide: getRepositoryToken(ViewFilterGroupEntity), + provide: getWorkspaceScopedRepositoryToken(ViewFilterGroupEntity), useValue: { find: jest.fn(), findOne: jest.fn(), - create: jest.fn(), save: jest.fn(), - softDelete: jest.fn(), delete: jest.fn(), }, }, @@ -65,9 +63,9 @@ describe('ViewFilterGroupService', () => { viewFilterGroupService = module.get( ViewFilterGroupService, ); - viewFilterGroupRepository = module.get>( - getRepositoryToken(ViewFilterGroupEntity), - ); + viewFilterGroupRepository = module.get< + WorkspaceScopedRepository + >(getWorkspaceScopedRepositoryToken(ViewFilterGroupEntity)); }); it('should be defined', () => { @@ -86,9 +84,8 @@ describe('ViewFilterGroupService', () => { const result = await viewFilterGroupService.findByWorkspaceId(workspaceId); - expect(viewFilterGroupRepository.find).toHaveBeenCalledWith({ + expect(viewFilterGroupRepository.find).toHaveBeenCalledWith(workspaceId, { where: { - workspaceId, deletedAt: expect.anything(), }, order: { positionInViewFilterGroup: 'ASC' }, @@ -119,9 +116,8 @@ describe('ViewFilterGroupService', () => { viewId, ); - expect(viewFilterGroupRepository.find).toHaveBeenCalledWith({ + expect(viewFilterGroupRepository.find).toHaveBeenCalledWith(workspaceId, { where: { - workspaceId, viewId, deletedAt: expect.anything(), }, @@ -149,20 +145,22 @@ describe('ViewFilterGroupService', () => { const result = await viewFilterGroupService.findById(id, workspaceId); - expect(viewFilterGroupRepository.findOne).toHaveBeenCalledWith({ - where: { - id, - workspaceId, - deletedAt: expect.anything(), + expect(viewFilterGroupRepository.findOne).toHaveBeenCalledWith( + workspaceId, + { + where: { + id, + deletedAt: expect.anything(), + }, + relations: [ + 'workspace', + 'view', + 'viewFilters', + 'parentViewFilterGroup', + 'childViewFilterGroups', + ], }, - relations: [ - 'workspace', - 'view', - 'viewFilters', - 'parentViewFilterGroup', - 'childViewFilterGroups', - ], - }); + ); expect(result).toEqual(mockViewFilterGroup); }); diff --git a/packages/twenty-server/src/engine/metadata-modules/view-filter-group/services/view-filter-group.service.ts b/packages/twenty-server/src/engine/metadata-modules/view-filter-group/services/view-filter-group.service.ts index be1643b3b1f..6823eddab6f 100644 --- a/packages/twenty-server/src/engine/metadata-modules/view-filter-group/services/view-filter-group.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/view-filter-group/services/view-filter-group.service.ts @@ -1,7 +1,6 @@ import { Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; -import { IsNull, type Repository } from 'typeorm'; +import { IsNull } from 'typeorm'; import { ApplicationService } from 'src/engine/core-modules/application/application.service'; import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; @@ -18,14 +17,16 @@ import { type UpdateViewFilterGroupInput } from 'src/engine/metadata-modules/vie import { type ViewFilterGroupDTO } from 'src/engine/metadata-modules/view-filter-group/dtos/view-filter-group.dto'; import { ViewFilterGroupEntity } from 'src/engine/metadata-modules/view-filter-group/entities/view-filter-group.entity'; import { fromFlatViewFilterGroupToViewFilterGroupDto } from 'src/engine/metadata-modules/view-filter-group/utils/from-flat-view-filter-group-to-view-filter-group-dto.util'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager/workspace-migration/exceptions/workspace-migration-builder-exception'; import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service'; @Injectable() export class ViewFilterGroupService { constructor( - @InjectRepository(ViewFilterGroupEntity) - private readonly viewFilterGroupRepository: Repository, + @InjectWorkspaceScopedRepository(ViewFilterGroupEntity) + private readonly viewFilterGroupRepository: WorkspaceScopedRepository, private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService, private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, private readonly applicationService: ApplicationService, @@ -320,9 +321,8 @@ export class ViewFilterGroupService { async findByWorkspaceId( workspaceId: string, ): Promise { - return this.viewFilterGroupRepository.find({ + return this.viewFilterGroupRepository.find(workspaceId, { where: { - workspaceId, deletedAt: IsNull(), }, order: { positionInViewFilterGroup: 'ASC' }, @@ -340,9 +340,8 @@ export class ViewFilterGroupService { workspaceId: string, viewId: string, ): Promise { - return this.viewFilterGroupRepository.find({ + return this.viewFilterGroupRepository.find(workspaceId, { where: { - workspaceId, viewId, deletedAt: IsNull(), }, @@ -361,20 +360,22 @@ export class ViewFilterGroupService { id: string, workspaceId: string, ): Promise { - const viewFilterGroup = await this.viewFilterGroupRepository.findOne({ - where: { - id, - workspaceId, - deletedAt: IsNull(), + const viewFilterGroup = await this.viewFilterGroupRepository.findOne( + workspaceId, + { + where: { + id, + deletedAt: IsNull(), + }, + relations: [ + 'workspace', + 'view', + 'viewFilters', + 'parentViewFilterGroup', + 'childViewFilterGroups', + ], }, - relations: [ - 'workspace', - 'view', - 'viewFilters', - 'parentViewFilterGroup', - 'childViewFilterGroups', - ], - }); + ); return viewFilterGroup || null; } diff --git a/packages/twenty-server/src/engine/metadata-modules/view-filter-group/view-filter-group.module.ts b/packages/twenty-server/src/engine/metadata-modules/view-filter-group/view-filter-group.module.ts index edba7ce2c89..78822c5a803 100644 --- a/packages/twenty-server/src/engine/metadata-modules/view-filter-group/view-filter-group.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/view-filter-group/view-filter-group.module.ts @@ -10,6 +10,7 @@ import { ViewFilterGroupResolver } from 'src/engine/metadata-modules/view-filter import { ViewFilterGroupService } from 'src/engine/metadata-modules/view-filter-group/services/view-filter-group.service'; import { ViewPermissionsModule } from 'src/engine/metadata-modules/view-permissions/view-permissions.module'; import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity'; +import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/provide-workspace-scoped-repository'; import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/workspace-cache-storage.module'; import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration.module'; @@ -24,7 +25,11 @@ import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace ViewPermissionsModule, ], controllers: [ViewFilterGroupController], - providers: [ViewFilterGroupService, ViewFilterGroupResolver], + providers: [ + ViewFilterGroupService, + ViewFilterGroupResolver, + provideWorkspaceScopedRepository(ViewFilterGroupEntity), + ], exports: [ViewFilterGroupService], }) export class ViewFilterGroupModule {} diff --git a/packages/twenty-server/src/engine/metadata-modules/view-filter/services/view-filter.service.ts b/packages/twenty-server/src/engine/metadata-modules/view-filter/services/view-filter.service.ts index 7ad56f040ba..0c40260c719 100644 --- a/packages/twenty-server/src/engine/metadata-modules/view-filter/services/view-filter.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/view-filter/services/view-filter.service.ts @@ -1,7 +1,6 @@ import { Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; -import { IsNull, Repository } from 'typeorm'; +import { IsNull } from 'typeorm'; import { ApplicationService } from 'src/engine/core-modules/application/application.service'; import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; @@ -18,14 +17,16 @@ import { UpdateViewFilterInput } from 'src/engine/metadata-modules/view-filter/d import { ViewFilterDTO } from 'src/engine/metadata-modules/view-filter/dtos/view-filter.dto'; import { ViewFilterEntity } from 'src/engine/metadata-modules/view-filter/entities/view-filter.entity'; import { fromFlatViewFilterToViewFilterDto } from 'src/engine/metadata-modules/view-filter/utils/from-flat-view-filter-to-view-filter-dto.util'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager/workspace-migration/exceptions/workspace-migration-builder-exception'; import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service'; @Injectable() export class ViewFilterService { constructor( - @InjectRepository(ViewFilterEntity) - private readonly viewFilterRepository: Repository, + @InjectWorkspaceScopedRepository(ViewFilterEntity) + private readonly viewFilterRepository: WorkspaceScopedRepository, private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService, private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, private readonly applicationService: ApplicationService, @@ -319,9 +320,8 @@ export class ViewFilterService { } async findByWorkspaceId(workspaceId: string): Promise { - return this.viewFilterRepository.find({ + return this.viewFilterRepository.find(workspaceId, { where: { - workspaceId, deletedAt: IsNull(), }, order: { positionInViewFilterGroup: 'ASC' }, @@ -333,9 +333,8 @@ export class ViewFilterService { workspaceId: string, viewId: string, ): Promise { - return this.viewFilterRepository.find({ + return this.viewFilterRepository.find(workspaceId, { where: { - workspaceId, viewId, deletedAt: IsNull(), }, @@ -348,10 +347,9 @@ export class ViewFilterService { id: string, workspaceId: string, ): Promise { - const viewFilter = await this.viewFilterRepository.findOne({ + const viewFilter = await this.viewFilterRepository.findOne(workspaceId, { where: { id, - workspaceId, deletedAt: IsNull(), }, relations: ['workspace', 'view', 'viewFilterGroup'], diff --git a/packages/twenty-server/src/engine/metadata-modules/view-filter/view-filter.module.ts b/packages/twenty-server/src/engine/metadata-modules/view-filter/view-filter.module.ts index 9788e3a0a38..7bc75297103 100644 --- a/packages/twenty-server/src/engine/metadata-modules/view-filter/view-filter.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/view-filter/view-filter.module.ts @@ -11,6 +11,7 @@ import { ViewFilterService } from 'src/engine/metadata-modules/view-filter/servi import { ViewFilterToolsFactory } from 'src/engine/metadata-modules/view-filter/tools/view-filter-tools.factory'; import { ViewPermissionsModule } from 'src/engine/metadata-modules/view-permissions/view-permissions.module'; import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity'; +import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/provide-workspace-scoped-repository'; import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/workspace-cache-storage.module'; import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration.module'; @@ -25,7 +26,12 @@ import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace ViewPermissionsModule, ], controllers: [ViewFilterController], - providers: [ViewFilterService, ViewFilterResolver, ViewFilterToolsFactory], + providers: [ + ViewFilterService, + ViewFilterResolver, + ViewFilterToolsFactory, + provideWorkspaceScopedRepository(ViewFilterEntity), + ], exports: [ViewFilterService, ViewFilterToolsFactory], }) export class ViewFilterModule {} diff --git a/packages/twenty-server/src/engine/metadata-modules/view-group/services/view-group.service.ts b/packages/twenty-server/src/engine/metadata-modules/view-group/services/view-group.service.ts index e2f1570781a..bc780a18e1a 100644 --- a/packages/twenty-server/src/engine/metadata-modules/view-group/services/view-group.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/view-group/services/view-group.service.ts @@ -1,8 +1,7 @@ import { Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; import { isDefined } from 'twenty-shared/utils'; -import { IsNull, Repository } from 'typeorm'; +import { IsNull } from 'typeorm'; import { ApplicationService } from 'src/engine/core-modules/application/application.service'; import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; @@ -25,14 +24,16 @@ import { ViewGroupExceptionCode, } from 'src/engine/metadata-modules/view-group/exceptions/view-group.exception'; import { fromFlatViewGroupToViewGroupDto } from 'src/engine/metadata-modules/view-group/utils/from-flat-view-group-to-view-group-dto.util'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager/workspace-migration/exceptions/workspace-migration-builder-exception'; import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service'; @Injectable() export class ViewGroupService { constructor( - @InjectRepository(ViewGroupEntity) - private readonly viewGroupRepository: Repository, + @InjectWorkspaceScopedRepository(ViewGroupEntity) + private readonly viewGroupRepository: WorkspaceScopedRepository, private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService, private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, private readonly applicationService: ApplicationService, @@ -379,9 +380,8 @@ export class ViewGroupService { } async findByWorkspaceId(workspaceId: string): Promise { - return this.viewGroupRepository.find({ + return this.viewGroupRepository.find(workspaceId, { where: { - workspaceId, deletedAt: IsNull(), }, order: { position: 'ASC' }, @@ -393,9 +393,8 @@ export class ViewGroupService { workspaceId: string, viewId: string, ): Promise { - return this.viewGroupRepository.find({ + return this.viewGroupRepository.find(workspaceId, { where: { - workspaceId, viewId, deletedAt: IsNull(), }, @@ -408,10 +407,9 @@ export class ViewGroupService { id: string, workspaceId: string, ): Promise { - const viewGroup = await this.viewGroupRepository.findOne({ + const viewGroup = await this.viewGroupRepository.findOne(workspaceId, { where: { id, - workspaceId, deletedAt: IsNull(), }, relations: ['workspace', 'view'], diff --git a/packages/twenty-server/src/engine/metadata-modules/view-group/view-group.module.ts b/packages/twenty-server/src/engine/metadata-modules/view-group/view-group.module.ts index 1b70680a54c..d76b6c55a7d 100644 --- a/packages/twenty-server/src/engine/metadata-modules/view-group/view-group.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/view-group/view-group.module.ts @@ -12,6 +12,7 @@ import { ViewGroupResolver } from 'src/engine/metadata-modules/view-group/resolv import { ViewGroupService } from 'src/engine/metadata-modules/view-group/services/view-group.service'; import { ViewPermissionsModule } from 'src/engine/metadata-modules/view-permissions/view-permissions.module'; import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity'; +import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/provide-workspace-scoped-repository'; import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/workspace-cache-storage.module'; import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration.module'; @@ -28,7 +29,11 @@ import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace ViewPermissionsModule, ], controllers: [ViewGroupController], - providers: [ViewGroupService, ViewGroupResolver], + providers: [ + ViewGroupService, + ViewGroupResolver, + provideWorkspaceScopedRepository(ViewGroupEntity), + ], exports: [ViewGroupService], }) export class ViewGroupModule {} diff --git a/packages/twenty-server/src/engine/metadata-modules/view-permissions/services/view-entity-lookup.service.ts b/packages/twenty-server/src/engine/metadata-modules/view-permissions/services/view-entity-lookup.service.ts index 1028de8b6a4..df53f0271de 100644 --- a/packages/twenty-server/src/engine/metadata-modules/view-permissions/services/view-entity-lookup.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/view-permissions/services/view-entity-lookup.service.ts @@ -1,7 +1,4 @@ import { Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; - -import { Repository } from 'typeorm'; import { ViewFieldEntity } from 'src/engine/metadata-modules/view-field/entities/view-field.entity'; import { ViewFilterGroupEntity } from 'src/engine/metadata-modules/view-filter-group/entities/view-filter-group.entity'; @@ -9,20 +6,22 @@ import { ViewFilterEntity } from 'src/engine/metadata-modules/view-filter/entiti import { ViewGroupEntity } from 'src/engine/metadata-modules/view-group/entities/view-group.entity'; import { type ViewChildEntityKind } from 'src/engine/metadata-modules/view-permissions/types/view-permissions.types'; import { ViewSortEntity } from 'src/engine/metadata-modules/view-sort/entities/view-sort.entity'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; @Injectable() export class ViewEntityLookupService { constructor( - @InjectRepository(ViewFieldEntity) - private readonly viewFieldRepository: Repository, - @InjectRepository(ViewFilterEntity) - private readonly viewFilterRepository: Repository, - @InjectRepository(ViewFilterGroupEntity) - private readonly viewFilterGroupRepository: Repository, - @InjectRepository(ViewGroupEntity) - private readonly viewGroupRepository: Repository, - @InjectRepository(ViewSortEntity) - private readonly viewSortRepository: Repository, + @InjectWorkspaceScopedRepository(ViewFieldEntity) + private readonly viewFieldRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(ViewFilterEntity) + private readonly viewFilterRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(ViewFilterGroupEntity) + private readonly viewFilterGroupRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(ViewGroupEntity) + private readonly viewGroupRepository: WorkspaceScopedRepository, + @InjectWorkspaceScopedRepository(ViewSortEntity) + private readonly viewSortRepository: WorkspaceScopedRepository, ) {} async findViewIdByEntityIdAndKind( @@ -32,8 +31,8 @@ export class ViewEntityLookupService { ): Promise { switch (kind) { case 'viewField': { - const row = await this.viewFieldRepository.findOne({ - where: { id: entityId, workspaceId }, + const row = await this.viewFieldRepository.findOne(workspaceId, { + where: { id: entityId }, select: ['viewId'], }); @@ -42,8 +41,8 @@ export class ViewEntityLookupService { } case 'viewFilter': { - const row = await this.viewFilterRepository.findOne({ - where: { id: entityId, workspaceId }, + const row = await this.viewFilterRepository.findOne(workspaceId, { + where: { id: entityId }, select: ['viewId'], }); @@ -52,8 +51,8 @@ export class ViewEntityLookupService { } case 'viewFilterGroup': { - const row = await this.viewFilterGroupRepository.findOne({ - where: { id: entityId, workspaceId }, + const row = await this.viewFilterGroupRepository.findOne(workspaceId, { + where: { id: entityId }, select: ['viewId'], }); @@ -62,8 +61,8 @@ export class ViewEntityLookupService { } case 'viewGroup': { - const row = await this.viewGroupRepository.findOne({ - where: { id: entityId, workspaceId }, + const row = await this.viewGroupRepository.findOne(workspaceId, { + where: { id: entityId }, select: ['viewId'], }); @@ -72,8 +71,8 @@ export class ViewEntityLookupService { } case 'viewSort': { - const row = await this.viewSortRepository.findOne({ - where: { id: entityId, workspaceId }, + const row = await this.viewSortRepository.findOne(workspaceId, { + where: { id: entityId }, select: ['viewId'], }); diff --git a/packages/twenty-server/src/engine/metadata-modules/view-permissions/view-permissions.module.ts b/packages/twenty-server/src/engine/metadata-modules/view-permissions/view-permissions.module.ts index 352843b6e2a..51bac9d65fd 100644 --- a/packages/twenty-server/src/engine/metadata-modules/view-permissions/view-permissions.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/view-permissions/view-permissions.module.ts @@ -38,6 +38,7 @@ import { ViewEntityLookupService } from 'src/engine/metadata-modules/view-permis import { ViewSortEntity } from 'src/engine/metadata-modules/view-sort/entities/view-sort.entity'; import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity'; import { ViewService } from 'src/engine/metadata-modules/view/services/view.service'; +import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/provide-workspace-scoped-repository'; import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/workspace-cache-storage.module'; import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration.module'; @@ -86,6 +87,12 @@ import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace UpdateViewSortPermissionGuard, DeleteViewSortPermissionGuard, DestroyViewSortPermissionGuard, + provideWorkspaceScopedRepository(ViewEntity), + provideWorkspaceScopedRepository(ViewFieldEntity), + provideWorkspaceScopedRepository(ViewFilterEntity), + provideWorkspaceScopedRepository(ViewFilterGroupEntity), + provideWorkspaceScopedRepository(ViewGroupEntity), + provideWorkspaceScopedRepository(ViewSortEntity), ], exports: [ ViewService, diff --git a/packages/twenty-server/src/engine/metadata-modules/view-sort/services/view-sort.service.ts b/packages/twenty-server/src/engine/metadata-modules/view-sort/services/view-sort.service.ts index e6ae6ddeb4c..7a8bfa44866 100644 --- a/packages/twenty-server/src/engine/metadata-modules/view-sort/services/view-sort.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/view-sort/services/view-sort.service.ts @@ -1,7 +1,6 @@ import { Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; -import { IsNull, Repository } from 'typeorm'; +import { IsNull } from 'typeorm'; import { ApplicationService } from 'src/engine/core-modules/application/application.service'; import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; @@ -18,14 +17,16 @@ import { UpdateViewSortInput } from 'src/engine/metadata-modules/view-sort/dtos/ import { ViewSortDTO } from 'src/engine/metadata-modules/view-sort/dtos/view-sort.dto'; import { ViewSortEntity } from 'src/engine/metadata-modules/view-sort/entities/view-sort.entity'; import { fromFlatViewSortToViewSortDto } from 'src/engine/metadata-modules/view-sort/utils/from-flat-view-sort-to-view-sort-dto.util'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager/workspace-migration/exceptions/workspace-migration-builder-exception'; import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service'; @Injectable() export class ViewSortService { constructor( - @InjectRepository(ViewSortEntity) - private readonly viewSortRepository: Repository, + @InjectWorkspaceScopedRepository(ViewSortEntity) + private readonly viewSortRepository: WorkspaceScopedRepository, private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService, private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, private readonly applicationService: ApplicationService, @@ -301,9 +302,8 @@ export class ViewSortService { } async findByWorkspaceId(workspaceId: string): Promise { - return this.viewSortRepository.find({ + return this.viewSortRepository.find(workspaceId, { where: { - workspaceId, deletedAt: IsNull(), }, relations: ['workspace', 'view'], @@ -314,9 +314,8 @@ export class ViewSortService { workspaceId: string, viewId: string, ): Promise { - return this.viewSortRepository.find({ + return this.viewSortRepository.find(workspaceId, { where: { - workspaceId, viewId, deletedAt: IsNull(), }, @@ -328,10 +327,9 @@ export class ViewSortService { id: string, workspaceId: string, ): Promise { - const viewSort = await this.viewSortRepository.findOne({ + const viewSort = await this.viewSortRepository.findOne(workspaceId, { where: { id, - workspaceId, deletedAt: IsNull(), }, relations: ['workspace', 'view'], diff --git a/packages/twenty-server/src/engine/metadata-modules/view-sort/view-sort.module.ts b/packages/twenty-server/src/engine/metadata-modules/view-sort/view-sort.module.ts index ba02fabdd4d..fa7f44a7c86 100644 --- a/packages/twenty-server/src/engine/metadata-modules/view-sort/view-sort.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/view-sort/view-sort.module.ts @@ -10,6 +10,7 @@ import { ViewSortResolver } from 'src/engine/metadata-modules/view-sort/resolver import { ViewSortService } from 'src/engine/metadata-modules/view-sort/services/view-sort.service'; import { ViewSortToolsFactory } from 'src/engine/metadata-modules/view-sort/tools/view-sort-tools.factory'; import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity'; +import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/provide-workspace-scoped-repository'; import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/workspace-cache-storage.module'; import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration.module'; import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module'; @@ -25,7 +26,12 @@ import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata ViewPermissionsModule, ], controllers: [ViewSortController], - providers: [ViewSortService, ViewSortResolver, ViewSortToolsFactory], + providers: [ + ViewSortService, + ViewSortResolver, + ViewSortToolsFactory, + provideWorkspaceScopedRepository(ViewSortEntity), + ], exports: [ViewSortService, ViewSortToolsFactory], }) export class ViewSortModule {} diff --git a/packages/twenty-server/src/engine/metadata-modules/view/services/view-widget-upsert.service.ts b/packages/twenty-server/src/engine/metadata-modules/view/services/view-widget-upsert.service.ts index 55fa291adae..837c870f14a 100644 --- a/packages/twenty-server/src/engine/metadata-modules/view/services/view-widget-upsert.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/view/services/view-widget-upsert.service.ts @@ -1,5 +1,4 @@ import { Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; import { t } from '@lingui/core/macro'; import { @@ -8,7 +7,7 @@ import { ViewSortDirection, } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; -import { IsNull, Repository } from 'typeorm'; +import { IsNull } from 'typeorm'; import { v4 } from 'uuid'; import { ApplicationService } from 'src/engine/core-modules/application/application.service'; @@ -43,6 +42,8 @@ import { ViewException, ViewExceptionCode, } from 'src/engine/metadata-modules/view/exceptions/view.exception'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager/workspace-migration/exceptions/workspace-migration-builder-exception'; import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service'; @@ -75,8 +76,8 @@ export class ViewWidgetUpsertService { private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService, private readonly workspaceManyOrAllFlatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, private readonly applicationService: ApplicationService, - @InjectRepository(ViewEntity) - private readonly viewRepository: Repository, + @InjectWorkspaceScopedRepository(ViewEntity) + private readonly viewRepository: WorkspaceScopedRepository, ) {} async upsertViewWidget({ @@ -186,13 +187,15 @@ export class ViewWidgetUpsertService { !isDefined(input.viewFilters) && !isDefined(input.viewSorts) ) { - const view = await this.viewRepository.findOne({ - where: { - id: upsertContext.viewId, - workspaceId: upsertContext.workspaceId, - deletedAt: IsNull(), + const view = await this.viewRepository.findOne( + upsertContext.workspaceId, + { + where: { + id: upsertContext.viewId, + deletedAt: IsNull(), + }, }, - }); + ); if (!isDefined(view)) { throw new ViewException( @@ -354,10 +357,9 @@ export class ViewWidgetUpsertService { ); } - const view = await this.viewRepository.findOne({ + const view = await this.viewRepository.findOne(upsertContext.workspaceId, { where: { id: upsertContext.viewId, - workspaceId: upsertContext.workspaceId, deletedAt: IsNull(), }, }); diff --git a/packages/twenty-server/src/engine/metadata-modules/view/services/view.service.ts b/packages/twenty-server/src/engine/metadata-modules/view/services/view.service.ts index f39b403501f..c475478a7b9 100644 --- a/packages/twenty-server/src/engine/metadata-modules/view/services/view.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/view/services/view.service.ts @@ -1,10 +1,8 @@ import { Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; import { APP_LOCALES, SOURCE_LOCALE } from 'twenty-shared/translations'; import { ViewType, ViewVisibility } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; -import { Repository } from 'typeorm'; import { ApplicationService } from 'src/engine/core-modules/application/application.service'; import { I18nService } from 'src/engine/core-modules/i18n/i18n.service'; @@ -32,14 +30,16 @@ import { UpdateViewInput } from 'src/engine/metadata-modules/view/dtos/inputs/up import { ViewDTO } from 'src/engine/metadata-modules/view/dtos/view.dto'; import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity'; import { fromFlatViewToViewDto } from 'src/engine/metadata-modules/view/utils/from-flat-view-to-view-dto.util'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager/workspace-migration/exceptions/workspace-migration-builder-exception'; import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service'; @Injectable() export class ViewService { constructor( - @InjectRepository(ViewEntity) - private readonly viewRepository: Repository, + @InjectWorkspaceScopedRepository(ViewEntity) + private readonly viewRepository: WorkspaceScopedRepository, private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService, private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, private readonly applicationService: ApplicationService, @@ -625,10 +625,9 @@ export class ViewService { id: string, workspaceId: string, ): Promise { - const view = await this.viewRepository.findOne({ + const view = await this.viewRepository.findOne(workspaceId, { where: { id, - workspaceId, }, relations: [ 'workspace', diff --git a/packages/twenty-server/src/engine/metadata-modules/view/view.module.ts b/packages/twenty-server/src/engine/metadata-modules/view/view.module.ts index c84edfd00fa..32477875f84 100644 --- a/packages/twenty-server/src/engine/metadata-modules/view/view.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/view/view.module.ts @@ -19,6 +19,7 @@ import { ViewResolver } from 'src/engine/metadata-modules/view/resolvers/view.re import { ViewQueryParamsService } from 'src/engine/metadata-modules/view/services/view-query-params.service'; import { ViewService } from 'src/engine/metadata-modules/view/services/view.service'; import { ViewToolsFactory } from 'src/engine/metadata-modules/view/tools/view-tools.factory'; +import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/provide-workspace-scoped-repository'; import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/workspace-cache-storage.module'; import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration.module'; @@ -46,6 +47,7 @@ import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace ViewQueryParamsService, ViewToolsFactory, ViewWidgetUpsertService, + provideWorkspaceScopedRepository(ViewEntity), ], exports: [ ViewService, diff --git a/packages/twenty-server/src/engine/metadata-modules/webhook/webhook.module.ts b/packages/twenty-server/src/engine/metadata-modules/webhook/webhook.module.ts index a8064f90b1f..13aa003e66b 100644 --- a/packages/twenty-server/src/engine/metadata-modules/webhook/webhook.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/webhook/webhook.module.ts @@ -13,6 +13,7 @@ import { WebhookGraphqlApiExceptionInterceptor } from 'src/engine/metadata-modul import { WebhookToolWorkspaceService } from 'src/engine/metadata-modules/webhook/tools/services/webhook-tool.workspace-service'; import { WebhookResolver } from 'src/engine/metadata-modules/webhook/webhook.resolver'; import { WebhookService } from 'src/engine/metadata-modules/webhook/webhook.service'; +import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/provide-workspace-scoped-repository'; import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/workspace-cache-storage.module'; import { WorkspaceMigrationGraphqlApiExceptionInterceptor } from 'src/engine/workspace-manager/workspace-migration/interceptors/workspace-migration-graphql-api-exception.interceptor'; import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration.module'; @@ -35,6 +36,7 @@ import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace WebhookGraphqlApiExceptionInterceptor, WorkspaceMigrationGraphqlApiExceptionInterceptor, WebhookToolWorkspaceService, + provideWorkspaceScopedRepository(WebhookEntity), ], exports: [WebhookService, WebhookToolWorkspaceService], }) diff --git a/packages/twenty-server/src/engine/metadata-modules/webhook/webhook.service.ts b/packages/twenty-server/src/engine/metadata-modules/webhook/webhook.service.ts index 5f03ac9aa7b..2f71ba0bff6 100644 --- a/packages/twenty-server/src/engine/metadata-modules/webhook/webhook.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/webhook/webhook.service.ts @@ -13,6 +13,8 @@ import { fromDeleteWebhookInputToFlatWebhookOrThrow } from 'src/engine/metadata- import { fromFlatWebhookToWebhookDto } from 'src/engine/metadata-modules/flat-webhook/utils/from-flat-webhook-to-webhook-dto.util'; import { fromUpdateWebhookInputToFlatWebhookToUpdateOrThrow } from 'src/engine/metadata-modules/flat-webhook/utils/from-update-webhook-input-to-flat-webhook-to-update-or-throw.util'; import { fromWebhookEntityToFlatWebhook } from 'src/engine/metadata-modules/flat-webhook/utils/from-webhook-entity-to-flat-webhook.util'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { type CreateWebhookInput } from 'src/engine/metadata-modules/webhook/dtos/create-webhook.input'; import { type UpdateWebhookInput } from 'src/engine/metadata-modules/webhook/dtos/update-webhook.input'; import { type WebhookDTO } from 'src/engine/metadata-modules/webhook/dtos/webhook.dto'; @@ -24,8 +26,8 @@ import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspa @Injectable() export class WebhookService { constructor( - @InjectRepository(WebhookEntity) - private readonly webhookRepository: Repository, + @InjectWorkspaceScopedRepository(WebhookEntity) + private readonly webhookRepository: WorkspaceScopedRepository, @InjectRepository(ApplicationEntity) private readonly applicationRepository: Repository, private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService, @@ -45,8 +47,8 @@ export class WebhookService { async findAll(workspaceId: string): Promise { const [webhooks, applications] = await Promise.all([ - this.webhookRepository.find({ - where: { workspaceId, deletedAt: IsNull() }, + this.webhookRepository.find(workspaceId, { + where: { deletedAt: IsNull() }, order: { createdAt: 'ASC' }, }), this.applicationRepository.find({ @@ -70,8 +72,8 @@ export class WebhookService { async findById(id: string, workspaceId: string): Promise { const [webhook, applications] = await Promise.all([ - this.webhookRepository.findOne({ - where: { id, workspaceId, deletedAt: IsNull() }, + this.webhookRepository.findOne(workspaceId, { + where: { id, deletedAt: IsNull() }, }), this.applicationRepository.find({ where: { workspaceId }, diff --git a/packages/twenty-server/src/engine/twenty-orm/workspace-scoped-repository/__tests__/workspace-scoped-repository.spec.ts b/packages/twenty-server/src/engine/twenty-orm/workspace-scoped-repository/__tests__/workspace-scoped-repository.spec.ts index 0f2a0cec79c..f58b0eb35d7 100644 --- a/packages/twenty-server/src/engine/twenty-orm/workspace-scoped-repository/__tests__/workspace-scoped-repository.spec.ts +++ b/packages/twenty-server/src/engine/twenty-orm/workspace-scoped-repository/__tests__/workspace-scoped-repository.spec.ts @@ -15,9 +15,16 @@ const createMockRepository = (): jest.Mocked> => ({ findOne: jest.fn().mockResolvedValue(null), findOneOrFail: jest.fn(), + findOneBy: jest.fn().mockResolvedValue(null), find: jest.fn().mockResolvedValue([]), count: jest.fn().mockResolvedValue(0), + findAndCount: jest.fn().mockResolvedValue([[], 0]), + exists: jest.fn().mockResolvedValue(false), + existsBy: jest.fn().mockResolvedValue(false), + maximum: jest.fn().mockResolvedValue(null), update: jest.fn(), + increment: jest.fn(), + decrement: jest.fn(), delete: jest.fn(), softDelete: jest.fn(), insert: jest.fn(), @@ -45,15 +52,22 @@ describe('WorkspaceScopedRepository', () => { 'findOneOrFail', () => scoped.findOneOrFail(undefined as never, { where: {} }), ], + ['findOneBy', () => scoped.findOneBy(undefined as never, {})], ['find', () => scoped.find(undefined as never)], ['count', () => scoped.count(undefined as never)], + ['findAndCount', () => scoped.findAndCount(undefined as never)], + ['exists', () => scoped.exists(undefined as never)], + ['existsBy', () => scoped.existsBy(undefined as never, {})], ['update', () => scoped.update(undefined as never, {}, {})], + ['increment', () => scoped.increment(undefined as never, {}, 'count', 1)], + ['decrement', () => scoped.decrement(undefined as never, {}, 'count', 1)], ['delete', () => scoped.delete(undefined as never, {})], ['softDelete', () => scoped.softDelete(undefined as never, {})], ['insert', () => scoped.insert(undefined as never, {})], ['upsert', () => scoped.upsert(undefined as never, {}, ['id'])], ['save', () => scoped.save(undefined as never, {})], ['saveMany', () => scoped.saveMany(undefined as never, [{}])], + ['maximum', () => scoped.maximum(undefined as never, 'id')], ])('%s throws when workspaceId is undefined', (_name, call) => { expect(call).toThrow(/workspaceId must be a non-empty string/); }); @@ -136,6 +150,28 @@ describe('WorkspaceScopedRepository', () => { }); }); + describe('findOneBy', () => { + it('merges workspaceId into where', async () => { + await scoped.findOneBy(WORKSPACE_ID, { id: 'a' }); + + expect(repository.findOneBy).toHaveBeenCalledWith({ + id: 'a', + workspaceId: WORKSPACE_ID, + }); + }); + + it('throws if the caller includes workspaceId in where', () => { + expect(() => + scoped.findOneBy(WORKSPACE_ID, { + id: 'a', + workspaceId: OTHER_WORKSPACE_ID, + } as never), + ).toThrow(/do not include `workspaceId`/); + + expect(repository.findOneBy).not.toHaveBeenCalled(); + }); + }); + describe('find', () => { it('adds workspaceId when no where is provided', async () => { await scoped.find(WORKSPACE_ID); @@ -154,6 +190,53 @@ describe('WorkspaceScopedRepository', () => { }); }); + describe('findAndCount', () => { + it('merges workspaceId into where', async () => { + await scoped.findAndCount(WORKSPACE_ID, { where: { status: 'queued' } }); + + expect(repository.findAndCount).toHaveBeenCalledWith({ + where: { status: 'queued', workspaceId: WORKSPACE_ID }, + }); + }); + + it('works without options', async () => { + await scoped.findAndCount(WORKSPACE_ID); + + expect(repository.findAndCount).toHaveBeenCalledWith({ + where: { workspaceId: WORKSPACE_ID }, + }); + }); + }); + + describe('exists', () => { + it('merges workspaceId into where', async () => { + await scoped.exists(WORKSPACE_ID, { where: { status: 'queued' } }); + + expect(repository.exists).toHaveBeenCalledWith({ + where: { status: 'queued', workspaceId: WORKSPACE_ID }, + }); + }); + + it('works without options', async () => { + await scoped.exists(WORKSPACE_ID); + + expect(repository.exists).toHaveBeenCalledWith({ + where: { workspaceId: WORKSPACE_ID }, + }); + }); + }); + + describe('existsBy', () => { + it('merges workspaceId into where', async () => { + await scoped.existsBy(WORKSPACE_ID, { id: 'a' }); + + expect(repository.existsBy).toHaveBeenCalledWith({ + id: 'a', + workspaceId: WORKSPACE_ID, + }); + }); + }); + describe('update', () => { it('merges workspaceId into the criteria, not the patch', async () => { await scoped.update(WORKSPACE_ID, { id: 'a' }, { status: 'completed' }); @@ -177,6 +260,41 @@ describe('WorkspaceScopedRepository', () => { }); }); + describe('increment and decrement', () => { + it('increment merges workspaceId into criteria', async () => { + await scoped.increment(WORKSPACE_ID, { id: 'a' }, 'count', 1); + + expect(repository.increment).toHaveBeenCalledWith( + { id: 'a', workspaceId: WORKSPACE_ID }, + 'count', + 1, + ); + }); + + it('increment throws if the caller includes workspaceId in the criteria', () => { + expect(() => + scoped.increment( + WORKSPACE_ID, + { id: 'a', workspaceId: OTHER_WORKSPACE_ID } as never, + 'count', + 1, + ), + ).toThrow(/do not include `workspaceId`/); + + expect(repository.increment).not.toHaveBeenCalled(); + }); + + it('decrement merges workspaceId into criteria', async () => { + await scoped.decrement(WORKSPACE_ID, { id: 'a' }, 'count', 1); + + expect(repository.decrement).toHaveBeenCalledWith( + { id: 'a', workspaceId: WORKSPACE_ID }, + 'count', + 1, + ); + }); + }); + describe('delete and softDelete', () => { it('delete merges workspaceId into criteria', async () => { await scoped.delete(WORKSPACE_ID, { id: 'a' }); @@ -319,6 +437,25 @@ describe('WorkspaceScopedRepository', () => { }); }); + describe('maximum', () => { + it('calls with scoped criteria when where is provided', async () => { + await scoped.maximum(WORKSPACE_ID, 'id', { status: 'queued' }); + + expect(repository.maximum).toHaveBeenCalledWith('id', { + status: 'queued', + workspaceId: WORKSPACE_ID, + }); + }); + + it('calls with only workspaceId when no where is given', async () => { + await scoped.maximum(WORKSPACE_ID, 'id'); + + expect(repository.maximum).toHaveBeenCalledWith('id', { + workspaceId: WORKSPACE_ID, + }); + }); + }); + describe('createQueryBuilder', () => { it('returns the underlying QueryBuilder unchanged (escape hatch)', () => { scoped.createQueryBuilder('t'); diff --git a/packages/twenty-server/src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository.ts b/packages/twenty-server/src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository.ts index 5569ae3d057..92b162e7a65 100644 --- a/packages/twenty-server/src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository.ts +++ b/packages/twenty-server/src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository.ts @@ -39,6 +39,17 @@ export class WorkspaceScopedRepository { }); } + findOneBy( + workspaceId: string, + where: FindOptionsWhere, + ): Promise { + this.assertWorkspaceId(workspaceId); + + return this.repository.findOneBy( + this.mergeWorkspaceIdIntoCriteria(workspaceId, where), + ); + } + find(workspaceId: string, options?: FindManyOptions): Promise { this.assertWorkspaceId(workspaceId); @@ -57,6 +68,51 @@ export class WorkspaceScopedRepository { }); } + findAndCount( + workspaceId: string, + options?: FindManyOptions, + ): Promise<[T[], number]> { + this.assertWorkspaceId(workspaceId); + + return this.repository.findAndCount({ + ...options, + where: this.mergeWorkspaceIdIntoWhere(workspaceId, options?.where), + }); + } + + exists(workspaceId: string, options?: FindManyOptions): Promise { + this.assertWorkspaceId(workspaceId); + + return this.repository.exists({ + ...options, + where: this.mergeWorkspaceIdIntoWhere(workspaceId, options?.where), + }); + } + + existsBy(workspaceId: string, where: FindOptionsWhere): Promise { + this.assertWorkspaceId(workspaceId); + + return this.repository.existsBy( + this.mergeWorkspaceIdIntoCriteria(workspaceId, where), + ); + } + + maximum( + workspaceId: string, + columnName: string, + where?: FindOptionsWhere, + ): Promise { + this.assertWorkspaceId(workspaceId); + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return this.repository.maximum( + columnName as any, + where + ? this.mergeWorkspaceIdIntoCriteria(workspaceId, where) + : ({ workspaceId } as FindOptionsWhere), + ); + } + update( workspaceId: string, criteria: FindOptionsWhere, @@ -70,6 +126,36 @@ export class WorkspaceScopedRepository { ); } + increment( + workspaceId: string, + criteria: FindOptionsWhere, + propertyPath: string, + value: number | string, + ): Promise { + this.assertWorkspaceId(workspaceId); + + return this.repository.increment( + this.mergeWorkspaceIdIntoCriteria(workspaceId, criteria), + propertyPath, + value, + ); + } + + decrement( + workspaceId: string, + criteria: FindOptionsWhere, + propertyPath: string, + value: number | string, + ): Promise { + this.assertWorkspaceId(workspaceId); + + return this.repository.decrement( + this.mergeWorkspaceIdIntoCriteria(workspaceId, criteria), + propertyPath, + value, + ); + } + delete( workspaceId: string, criteria: FindOptionsWhere, @@ -92,6 +178,14 @@ export class WorkspaceScopedRepository { ); } + // softRemove / recover / remove are intentionally absent. + // TypeORM's entity-based methods use only the primary key in the WHERE + // clause — stamping workspaceId on the entity object does not add an + // AND workspace_id = ? guard to the SQL. A leaked entity id could + // therefore act on a row from a different workspace. + // Use softDelete / delete (criteria-based) instead — they always include + // workspaceId in the WHERE clause. + insert( workspaceId: string, entity: QueryDeepPartialEntity | QueryDeepPartialEntity[], diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/services/dev-seeder-permissions.service.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/services/dev-seeder-permissions.service.ts index b8d193669af..1626fcc6b46 100644 --- a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/services/dev-seeder-permissions.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/services/dev-seeder-permissions.service.ts @@ -14,6 +14,8 @@ import { RoleDTO } from 'src/engine/metadata-modules/role/dtos/role.dto'; import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; import { RoleService } from 'src/engine/metadata-modules/role/role.service'; import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role.service'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { SEED_APPLE_WORKSPACE_ID, SEED_YCOMBINATOR_WORKSPACE_ID, @@ -35,8 +37,8 @@ export class DevSeederPermissionsService { private readonly objectPermissionService: ObjectPermissionService, @InjectRepository(ObjectMetadataEntity) private readonly objectMetadataRepository: Repository, - @InjectRepository(RoleEntity) - private readonly roleRepository: Repository, + @InjectWorkspaceScopedRepository(RoleEntity) + private readonly roleRepository: WorkspaceScopedRepository, private readonly fieldPermissionService: FieldPermissionService, private readonly roleTargetService: RoleTargetService, @InjectDataSource() @@ -54,10 +56,9 @@ export class DevSeederPermissionsService { workspaceCustomFlatApplication: FlatApplication; light?: boolean; }) { - const adminRole = await this.roleRepository.findOne({ + const adminRole = await this.roleRepository.findOne(workspaceId, { where: { universalIdentifier: STANDARD_ROLE.admin.universalIdentifier, - workspaceId, }, }); diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/dev-seeder.module.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/dev-seeder.module.ts index a49d001ff4b..66666bb0bdf 100644 --- a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/dev-seeder.module.ts +++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/dev-seeder.module.ts @@ -15,9 +15,11 @@ import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadat import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module'; import { ObjectPermissionModule } from 'src/engine/metadata-modules/object-permission/object-permission.module'; import { RoleTargetModule } from 'src/engine/metadata-modules/role-target/role-target.module'; +import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; import { RoleModule } from 'src/engine/metadata-modules/role/role.module'; import { UserRoleModule } from 'src/engine/metadata-modules/user-role/user-role.module'; import { UpgradeModule } from 'src/engine/core-modules/upgrade/upgrade.module'; +import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/provide-workspace-scoped-repository'; import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/workspace-cache-storage.module'; import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module'; import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; @@ -62,6 +64,7 @@ import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace DevSeederPermissionsService, DevSeederDataService, TimelineActivitySeederService, + provideWorkspaceScopedRepository(RoleEntity), ], }) export class DevSeederModule {} diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-manager.module.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-manager.module.ts index 9a73d768b84..829df2efa3b 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-manager.module.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-manager.module.ts @@ -15,6 +15,7 @@ import { RoleTargetEntity } from 'src/engine/metadata-modules/role-target/role-t import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; import { RoleModule } from 'src/engine/metadata-modules/role/role.module'; import { UserRoleModule } from 'src/engine/metadata-modules/user-role/user-role.module'; +import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/provide-workspace-scoped-repository'; import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; import { DevSeederModule } from 'src/engine/workspace-manager/dev-seeder/dev-seeder.module'; import { TwentyStandardApplicationModule } from 'src/engine/workspace-manager/twenty-standard-application/twenty-standard-application.module'; @@ -45,6 +46,9 @@ import { WorkspaceManagerService } from './workspace-manager.service'; ]), ], exports: [WorkspaceManagerService], - providers: [WorkspaceManagerService], + providers: [ + WorkspaceManagerService, + provideWorkspaceScopedRepository(RoleEntity), + ], }) export class WorkspaceManagerModule {} diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-manager.service.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-manager.service.ts index 8404f5e981d..63ffcbf1687 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-manager.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-manager.service.ts @@ -10,6 +10,8 @@ import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.ent import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; import { RoleService } from 'src/engine/metadata-modules/role/role.service'; import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role.service'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; import { STANDARD_ROLE } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-role.constant'; import { TwentyStandardApplicationService } from 'src/engine/workspace-manager/twenty-standard-application/services/twenty-standard-application.service'; @@ -27,8 +29,8 @@ export class WorkspaceManagerService { private readonly twentyStandardApplicationService: TwentyStandardApplicationService, @InjectRepository(WorkspaceEntity) private readonly workspaceRepository: Repository, - @InjectRepository(RoleEntity) - private readonly roleRepository: Repository, + @InjectWorkspaceScopedRepository(RoleEntity) + private readonly roleRepository: WorkspaceScopedRepository, private readonly applicationService: ApplicationService, ) {} @@ -97,10 +99,9 @@ export class WorkspaceManagerService { userId: string; workspaceCustomFlatApplication: FlatApplication; }): Promise { - const adminRole = await this.roleRepository.findOne({ + const adminRole = await this.roleRepository.findOne(workspaceId, { where: { universalIdentifier: STANDARD_ROLE.admin.universalIdentifier, - workspaceId, }, }); diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/calendar-event-import-manager.module.ts b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/calendar-event-import-manager.module.ts index 60f1c034164..77a20b38987 100644 --- a/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/calendar-event-import-manager.module.ts +++ b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/calendar-event-import-manager.module.ts @@ -10,6 +10,7 @@ import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user import { CalendarChannelEntity } from 'src/engine/metadata-modules/calendar-channel/entities/calendar-channel.entity'; import { ConnectedAccountEntity } from 'src/engine/metadata-modules/connected-account/entities/connected-account.entity'; import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module'; +import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/provide-workspace-scoped-repository'; import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; import { BlocklistWorkspaceEntity } from 'src/modules/blocklist/standard-objects/blocklist.workspace-entity'; import { CalendarEventCleanerModule } from 'src/modules/calendar/calendar-event-cleaner/calendar-event-cleaner.module'; @@ -66,6 +67,7 @@ import { RefreshTokensManagerModule } from 'src/modules/connected-account/refres FeatureFlagModule, ], providers: [ + provideWorkspaceScopedRepository(CalendarChannelEntity), CalendarChannelSyncStatusService, CalendarEventsImportService, CalendarFetchEventsService, diff --git a/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/services/calendar-event-import-exception-handler.service.ts b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/services/calendar-event-import-exception-handler.service.ts index 76889412ee7..5176809fcea 100644 --- a/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/services/calendar-event-import-exception-handler.service.ts +++ b/packages/twenty-server/src/modules/calendar/calendar-event-import-manager/services/calendar-event-import-exception-handler.service.ts @@ -1,17 +1,17 @@ import { Injectable, Logger } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; - -import { Repository } from 'typeorm'; import { ExceptionHandlerService } from 'src/engine/core-modules/exception-handler/exception-handler.service'; -import { - type TwentyORMException, - TwentyORMExceptionCode, -} from 'src/engine/twenty-orm/exceptions/twenty-orm.exception'; +import { CalendarChannelEntity } from 'src/engine/metadata-modules/calendar-channel/entities/calendar-channel.entity'; import { ConnectedAccountRefreshAccessTokenException, ConnectedAccountRefreshAccessTokenExceptionCode, } from 'src/engine/metadata-modules/connected-account/exceptions/connected-account-refresh-tokens.exception'; +import { + type TwentyORMException, + TwentyORMExceptionCode, +} from 'src/engine/twenty-orm/exceptions/twenty-orm.exception'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { CALENDAR_THROTTLE_MAX_ATTEMPTS } from 'src/modules/calendar/calendar-event-import-manager/constants/calendar-throttle-max-attempts'; import { type CalendarEventImportDriverException, @@ -22,7 +22,6 @@ import { CalendarEventImportExceptionCode, } from 'src/modules/calendar/calendar-event-import-manager/exceptions/calendar-event-import.exception'; import { CalendarChannelSyncStatusService } from 'src/modules/calendar/common/services/calendar-channel-sync-status.service'; -import { CalendarChannelEntity } from 'src/engine/metadata-modules/calendar-channel/entities/calendar-channel.entity'; export enum CalendarEventImportSyncStep { CALENDAR_EVENT_LIST_FETCH = 'CALENDAR_EVENT_LIST_FETCH', CALENDAR_EVENTS_IMPORT = 'CALENDAR_EVENTS_IMPORT', @@ -34,8 +33,8 @@ export class CalendarEventImportErrorHandlerService { CalendarEventImportErrorHandlerService.name, ); constructor( - @InjectRepository(CalendarChannelEntity) - private readonly calendarChannelRepository: Repository, + @InjectWorkspaceScopedRepository(CalendarChannelEntity) + private readonly calendarChannelRepository: WorkspaceScopedRepository, private readonly calendarChannelSyncStatusService: CalendarChannelSyncStatusService, private readonly exceptionHandlerService: ExceptionHandlerService, ) {} @@ -142,7 +141,8 @@ export class CalendarEventImportErrorHandlerService { } await this.calendarChannelRepository.increment( - { id: calendarChannel.id, workspaceId }, + workspaceId, + { id: calendarChannel.id }, 'throttleFailureCount', 1, ); diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/messaging-import-manager.module.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/messaging-import-manager.module.ts index 95e1effc22c..ca9e7d04e3a 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/messaging-import-manager.module.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/messaging-import-manager.module.ts @@ -55,6 +55,7 @@ import { MessagingProcessFolderActionsService } from 'src/modules/messaging/mess import { MessagingProcessGroupEmailActionsService } from 'src/modules/messaging/message-import-manager/services/messaging-process-group-email-actions.service'; import { MessagingSaveMessagesAndEnqueueContactCreationService } from 'src/modules/messaging/message-import-manager/services/messaging-save-messages-and-enqueue-contact-creation.service'; import { MessagingWebhooksModule } from 'src/engine/core-modules/messaging-webhooks/messaging-webhooks.module'; +import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/provide-workspace-scoped-repository'; import { MessageParticipantManagerModule } from 'src/modules/messaging/message-participant-manager/message-participant-manager.module'; import { MessagingMonitoringModule } from 'src/modules/messaging/monitoring/messaging-monitoring.module'; @Module({ @@ -88,6 +89,7 @@ import { MessagingMonitoringModule } from 'src/modules/messaging/monitoring/mess MessagingWebhooksModule, ], providers: [ + provideWorkspaceScopedRepository(MessageChannelEntity), MessagingMessageListFetchCronCommand, MessagingMessagesImportCronCommand, MessagingOngoingStaleCronCommand, diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/services/__tests__/messaging-import-exception-handler.service.spec.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/services/__tests__/messaging-import-exception-handler.service.spec.ts index 25c111bc58f..0b99c181934 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/services/__tests__/messaging-import-exception-handler.service.spec.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/services/__tests__/messaging-import-exception-handler.service.spec.ts @@ -1,5 +1,4 @@ import { Test, type TestingModule } from '@nestjs/testing'; -import { getRepositoryToken } from '@nestjs/typeorm'; import { MessageChannelSyncStatus } from 'twenty-shared/types'; @@ -8,13 +7,14 @@ import { ConnectedAccountRefreshAccessTokenException, ConnectedAccountRefreshAccessTokenExceptionCode, } from 'src/engine/metadata-modules/connected-account/exceptions/connected-account-refresh-tokens.exception'; +import { MessageChannelEntity } from 'src/engine/metadata-modules/message-channel/entities/message-channel.entity'; +import { getWorkspaceScopedRepositoryToken } from 'src/engine/twenty-orm/workspace-scoped-repository/get-workspace-scoped-repository-token.util'; import { MessageChannelSyncStatusService } from 'src/modules/messaging/common/services/message-channel-sync-status.service'; import { MessageImportExceptionHandlerService, MessageImportSyncStep, } from 'src/modules/messaging/message-import-manager/services/messaging-import-exception-handler.service'; import { MessagingMonitoringService } from 'src/modules/messaging/monitoring/services/messaging-monitoring.service'; -import { MessageChannelEntity } from 'src/engine/metadata-modules/message-channel/entities/message-channel.entity'; describe('MessageImportExceptionHandlerService — refresh code dispatch', () => { let service: MessageImportExceptionHandlerService; @@ -50,7 +50,7 @@ describe('MessageImportExceptionHandlerService — refresh code dispatch', () => providers: [ MessageImportExceptionHandlerService, { - provide: getRepositoryToken(MessageChannelEntity), + provide: getWorkspaceScopedRepositoryToken(MessageChannelEntity), useValue: messageChannelRepository, }, { diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/services/messaging-import-exception-handler.service.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/services/messaging-import-exception-handler.service.ts index 86b641b2a0e..893b9b207ba 100644 --- a/packages/twenty-server/src/modules/messaging/message-import-manager/services/messaging-import-exception-handler.service.ts +++ b/packages/twenty-server/src/modules/messaging/message-import-manager/services/messaging-import-exception-handler.service.ts @@ -1,19 +1,20 @@ import { Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; import { isDefined } from 'twenty-shared/utils'; -import { Repository } from 'typeorm'; import { MessageChannelSyncStatus } from 'twenty-shared/types'; import { ExceptionHandlerService } from 'src/engine/core-modules/exception-handler/exception-handler.service'; -import { - type TwentyORMException, - TwentyORMExceptionCode, -} from 'src/engine/twenty-orm/exceptions/twenty-orm.exception'; +import { MessageChannelEntity } from 'src/engine/metadata-modules/message-channel/entities/message-channel.entity'; import { ConnectedAccountRefreshAccessTokenException, ConnectedAccountRefreshAccessTokenExceptionCode, } from 'src/engine/metadata-modules/connected-account/exceptions/connected-account-refresh-tokens.exception'; +import { + type TwentyORMException, + TwentyORMExceptionCode, +} from 'src/engine/twenty-orm/exceptions/twenty-orm.exception'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { MessageChannelSyncStatusService } from 'src/modules/messaging/common/services/message-channel-sync-status.service'; import { MESSAGING_THROTTLE_MAX_ATTEMPTS } from 'src/modules/messaging/message-import-manager/constants/messaging-throttle-max-attempts'; import { @@ -22,7 +23,6 @@ import { } from 'src/modules/messaging/message-import-manager/drivers/exceptions/message-import-driver.exception'; import { MessageNetworkExceptionCode } from 'src/modules/messaging/message-import-manager/drivers/exceptions/message-network.exception'; import { MessagingMonitoringService } from 'src/modules/messaging/monitoring/services/messaging-monitoring.service'; -import { MessageChannelEntity } from 'src/engine/metadata-modules/message-channel/entities/message-channel.entity'; export enum MessageImportSyncStep { MESSAGE_LIST_FETCH = 'MESSAGE_LIST_FETCH', @@ -33,8 +33,8 @@ export enum MessageImportSyncStep { @Injectable() export class MessageImportExceptionHandlerService { constructor( - @InjectRepository(MessageChannelEntity) - private readonly messageChannelRepository: Repository, + @InjectWorkspaceScopedRepository(MessageChannelEntity) + private readonly messageChannelRepository: WorkspaceScopedRepository, private readonly messageChannelSyncStatusService: MessageChannelSyncStatusService, private readonly exceptionHandlerService: ExceptionHandlerService, private readonly messagingMonitoringService: MessagingMonitoringService, @@ -183,7 +183,8 @@ export class MessageImportExceptionHandlerService { } await this.messageChannelRepository.increment( - { id: messageChannel.id, workspaceId }, + workspaceId, + { id: messageChannel.id }, 'throttleFailureCount', 1, ); @@ -194,7 +195,8 @@ export class MessageImportExceptionHandlerService { : undefined; await this.messageChannelRepository.update( - { id: messageChannel.id, workspaceId }, + workspaceId, + { id: messageChannel.id }, { throttleRetryAfter: isDefined(throttleRetryAfter) ? throttleRetryAfter.toISOString() diff --git a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/__tests__/workflow-version-step-operations.workspace-service.spec.ts b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/__tests__/workflow-version-step-operations.workspace-service.spec.ts index 61c4374c7b9..5aef09efb80 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/__tests__/workflow-version-step-operations.workspace-service.spec.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/__tests__/workflow-version-step-operations.workspace-service.spec.ts @@ -12,6 +12,7 @@ import { LogicFunctionFromSourceService } from 'src/engine/metadata-modules/logi import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { RoleTargetEntity } from 'src/engine/metadata-modules/role-target/role-target.entity'; import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; +import { getWorkspaceScopedRepositoryToken } from 'src/engine/twenty-orm/workspace-scoped-repository/get-workspace-scoped-repository-token.util'; import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service'; import { CodeStepBuildService } from 'src/modules/workflow/workflow-builder/workflow-version-step/code-step/services/code-step-build.service'; @@ -143,7 +144,7 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => { useValue: agentService, }, { - provide: getRepositoryToken(RoleTargetEntity), + provide: getWorkspaceScopedRepositoryToken(RoleTargetEntity), useValue: roleTargetRepository, }, { diff --git a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/workflow-version-step-operations.workspace-service.ts b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/workflow-version-step-operations.workspace-service.ts index 6c8b76486cc..32c9d86f524 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/workflow-version-step-operations.workspace-service.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/workflow-version-step-operations.workspace-service.ts @@ -27,6 +27,8 @@ import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadat import { RoleTargetEntity } from 'src/engine/metadata-modules/role-target/role-target.entity'; import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; import { buildSystemAuthContext } from 'src/engine/twenty-orm/utils/build-system-auth-context.util'; +import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; +import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; import { WorkflowVersionStepException, @@ -70,8 +72,8 @@ export class WorkflowVersionStepOperationsWorkspaceService { private readonly logicFunctionFromSourceService: LogicFunctionFromSourceService, private readonly codeStepBuildService: CodeStepBuildService, private readonly agentService: AgentService, - @InjectRepository(RoleTargetEntity) - private readonly roleTargetRepository: Repository, + @InjectWorkspaceScopedRepository(RoleTargetEntity) + private readonly roleTargetRepository: WorkspaceScopedRepository, @InjectRepository(ObjectMetadataEntity) private readonly objectMetadataRepository: Repository, private readonly workflowCommonWorkspaceService: WorkflowCommonWorkspaceService, @@ -100,12 +102,14 @@ export class WorkflowVersionStepOperationsWorkspaceService { break; } - const roleTarget = await this.roleTargetRepository.findOne({ - where: { - agentId: step.settings.input.agentId, - workspaceId, + const roleTarget = await this.roleTargetRepository.findOne( + workspaceId, + { + where: { + agentId: step.settings.input.agentId, + }, }, - }); + ); await this.agentService.deleteManyAgents({ ids: [step.settings.input.agentId], diff --git a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/workflow-version-step.module.ts b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/workflow-version-step.module.ts index 4813f253dca..c8014bb5062 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/workflow-version-step.module.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/workflow-version-step.module.ts @@ -9,6 +9,7 @@ import { LogicFunctionModule } from 'src/engine/metadata-modules/logic-function/ import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { RoleTargetEntity } from 'src/engine/metadata-modules/role-target/role-target.entity'; import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; +import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/provide-workspace-scoped-repository'; import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module'; import { WorkflowCommonModule } from 'src/modules/workflow/common/workflow-common.module'; import { WorkflowSchemaModule } from 'src/modules/workflow/workflow-builder/workflow-schema/workflow-schema.module'; @@ -43,6 +44,7 @@ import { WorkflowVersionStepWorkspaceService } from 'src/modules/workflow/workfl WorkflowVersionStepCreationWorkspaceService, WorkflowVersionStepUpdateWorkspaceService, WorkflowVersionStepDeletionWorkspaceService, + provideWorkspaceScopedRepository(RoleTargetEntity), ], exports: [ WorkflowVersionStepWorkspaceService,