fix: Add reserved subdomains constant and update validation on generateSubdomain (#15217)

## Description

Fixes #15160 

- Moved the reserved subdomains to a separate shared constant file:
`packages/twenty-server/src/engine/core-modules/workspace/constants/reserved-subdomains.constant.ts`
- Updated the validation while generating subdomain to check if the
extracted subdomain (from email or display name) is reserved
- When a reserved subdomain is detected, the server will automatically
fall back to a random subdomain

---------

Co-authored-by: Naineel Soyantar <naineelsoyantar@gmail.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Naineel Soyantar
2025-10-21 20:23:48 +05:30
committed by GitHub
parent 139b6dd29b
commit 26e432d8e2
97 changed files with 1369 additions and 754 deletions
@@ -13,8 +13,9 @@ import { parseCoreBatchPath } from 'src/engine/api/rest/core/query-builder/utils
import { parseCorePath } from 'src/engine/api/rest/core/query-builder/utils/path-parsers/parse-core-path.utils';
import { type Query } from 'src/engine/api/rest/core/types/query.type';
import { AccessTokenService } from 'src/engine/core-modules/auth/token/services/access-token.service';
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/services/domain-manager.service';
import { WorkspaceDomainsService } from 'src/engine/core-modules/domain/workspace-domains/services/workspace-domains.service';
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
import { WorkspaceNotFoundDefaultError } from 'src/engine/core-modules/workspace/workspace.exception';
import { type ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
import { type ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
import { getObjectMetadataMapItemByNamePlural } from 'src/engine/metadata-modules/utils/get-object-metadata-map-item-by-name-plural.util';
@@ -23,7 +24,6 @@ import { WorkspaceMetadataCacheService } from 'src/engine/metadata-modules/works
import { WorkspaceCacheStorageService } from 'src/engine/workspace-cache-storage/workspace-cache-storage.service';
import { standardObjectMetadataDefinitions } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-objects';
import { shouldExcludeFromWorkspaceApi } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/should-exclude-from-workspace-api.util';
import { WorkspaceNotFoundDefaultError } from 'src/engine/core-modules/workspace/workspace.exception';
@Injectable()
export class CoreQueryBuilderFactory {
@@ -33,7 +33,7 @@ export class CoreQueryBuilderFactory {
private readonly findDuplicatesQueryFactory: FindDuplicatesQueryFactory,
private readonly findDuplicatesVariablesFactory: FindDuplicatesVariablesFactory,
private readonly accessTokenService: AccessTokenService,
private readonly domainManagerService: DomainManagerService,
private readonly workspaceDomainsService: WorkspaceDomainsService,
private readonly workspaceCacheStorageService: WorkspaceCacheStorageService,
private readonly workspaceMetadataCacheService: WorkspaceMetadataCacheService,
private readonly featureFlagService: FeatureFlagService,
@@ -69,7 +69,7 @@ export class CoreQueryBuilderFactory {
if (!objectMetadataMaps) {
throw new BadRequestException(
`No object was found for the workspace associated with this API key. You may generate a new one here ${this.domainManagerService
`No object was found for the workspace associated with this API key. You may generate a new one here ${this.workspaceDomainsService
.buildWorkspaceURL({
workspace,
pathname: getSettingsPath(SettingsPath.ApiWebhooks),
@@ -4,7 +4,7 @@ import { CoreQueryBuilderFactory } from 'src/engine/api/rest/core/query-builder/
import { coreQueryBuilderFactories } from 'src/engine/api/rest/core/query-builder/factories/factories';
import { ApiKeyModule } from 'src/engine/core-modules/api-key/api-key.module';
import { AuthModule } from 'src/engine/core-modules/auth/auth.module';
import { DomainManagerModule } from 'src/engine/core-modules/domain-manager/domain-manager.module';
import { WorkspaceDomainsModule } from 'src/engine/core-modules/domain/workspace-domains/workspace-domains.module';
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
import { WorkspaceMetadataCacheModule } from 'src/engine/metadata-modules/workspace-metadata-cache/workspace-metadata-cache.module';
import { WorkspacePermissionsCacheModule } from 'src/engine/metadata-modules/workspace-permissions-cache/workspace-permissions-cache.module';
@@ -14,7 +14,7 @@ import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/
imports: [
AuthModule,
ApiKeyModule,
DomainManagerModule,
WorkspaceDomainsModule,
FeatureFlagModule,
WorkspaceCacheStorageModule,
WorkspaceMetadataCacheModule,
@@ -19,7 +19,6 @@ import { RestApiService } from 'src/engine/api/rest/rest-api.service';
import { ActorModule } from 'src/engine/core-modules/actor/actor.module';
import { ApiKeyModule } from 'src/engine/core-modules/api-key/api-key.module';
import { AuthModule } from 'src/engine/core-modules/auth/auth.module';
import { DomainManagerModule } from 'src/engine/core-modules/domain-manager/domain-manager.module';
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
import { RecordTransformerModule } from 'src/engine/core-modules/record-transformer/record-transformer.module';
import { UserRoleModule } from 'src/engine/metadata-modules/user-role/user-role.module';
@@ -54,7 +53,6 @@ const restApiCoreResolvers = [
ActorModule,
FeatureFlagModule,
CoreCommonApiModule,
DomainManagerModule,
],
controllers: [RestApiCoreController],
providers: [