rename core-module environment to twenty-config (#11445)

closes https://github.com/twentyhq/core-team-issues/issues/759
This commit is contained in:
nitin
2025-04-09 17:41:26 +05:30
committed by GitHub
parent fe6d0241a8
commit bd3ec6d5e3
193 changed files with 1454 additions and 1422 deletions

View File

@ -1,22 +1,22 @@
import { Test, TestingModule } from '@nestjs/testing';
import { getRepositoryToken } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Request, Response } from 'express';
import { Repository } from 'typeorm';
import { CloudflareController } from 'src/engine/core-modules/domain-manager/controllers/cloudflare.controller';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/services/domain-manager.service';
import { ExceptionHandlerService } from 'src/engine/core-modules/exception-handler/exception-handler.service';
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
import { HttpExceptionHandlerService } from 'src/engine/core-modules/exception-handler/http-exception-handler.service';
import { CustomDomainValidRecords } from 'src/engine/core-modules/domain-manager/dtos/custom-domain-valid-records';
import { CustomDomainService } from 'src/engine/core-modules/domain-manager/services/custom-domain.service';
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/services/domain-manager.service';
import { ExceptionHandlerService } from 'src/engine/core-modules/exception-handler/exception-handler.service';
import { HttpExceptionHandlerService } from 'src/engine/core-modules/exception-handler/http-exception-handler.service';
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
describe('CloudflareController - customHostnameWebhooks', () => {
let controller: CloudflareController;
let WorkspaceRepository: Repository<Workspace>;
let environmentService: EnvironmentService;
let twentyConfigService: TwentyConfigService;
let domainManagerService: DomainManagerService;
let customDomainService: CustomDomainService;
@ -56,7 +56,7 @@ describe('CloudflareController - customHostnameWebhooks', () => {
},
},
{
provide: EnvironmentService,
provide: TwentyConfigService,
useValue: {
get: jest.fn(),
},
@ -66,7 +66,7 @@ describe('CloudflareController - customHostnameWebhooks', () => {
controller = module.get<CloudflareController>(CloudflareController);
WorkspaceRepository = module.get(getRepositoryToken(Workspace, 'core'));
environmentService = module.get<EnvironmentService>(EnvironmentService);
twentyConfigService = module.get<TwentyConfigService>(TwentyConfigService);
domainManagerService =
module.get<DomainManagerService>(DomainManagerService);
customDomainService = module.get<CustomDomainService>(CustomDomainService);
@ -83,7 +83,7 @@ describe('CloudflareController - customHostnameWebhooks', () => {
send: sendMock,
} as unknown as Response;
jest.spyOn(environmentService, 'get').mockReturnValue('correct-secret');
jest.spyOn(twentyConfigService, 'get').mockReturnValue('correct-secret');
await controller.customHostnameWebhooks(req, res);
@ -102,7 +102,7 @@ describe('CloudflareController - customHostnameWebhooks', () => {
send: sendMock,
} as unknown as Response;
jest.spyOn(environmentService, 'get').mockReturnValue('correct-secret');
jest.spyOn(twentyConfigService, 'get').mockReturnValue('correct-secret');
jest
.spyOn(customDomainService, 'getCustomDomainDetails')
.mockResolvedValue({
@ -147,7 +147,7 @@ describe('CloudflareController - customHostnameWebhooks', () => {
send: sendMock,
} as unknown as Response;
jest.spyOn(environmentService, 'get').mockReturnValue('correct-secret');
jest.spyOn(twentyConfigService, 'get').mockReturnValue('correct-secret');
jest.spyOn(WorkspaceRepository, 'findOneBy').mockResolvedValue({
customDomain: 'notfound.com',
isCustomDomainEnabled: true,
@ -180,7 +180,7 @@ describe('CloudflareController - customHostnameWebhooks', () => {
send: sendMock,
} as unknown as Response;
jest.spyOn(environmentService, 'get').mockReturnValue('correct-secret');
jest.spyOn(twentyConfigService, 'get').mockReturnValue('correct-secret');
jest.spyOn(WorkspaceRepository, 'findOneBy').mockResolvedValue({
customDomain: 'nothing-change.com',
isCustomDomainEnabled: true,

View File

@ -4,17 +4,17 @@ import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { timingSafeEqual } from 'crypto';
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
@Injectable()
export class CloudflareSecretMatchGuard implements CanActivate {
constructor(private readonly environmentService: EnvironmentService) {}
constructor(private readonly twentyConfigService: TwentyConfigService) {}
canActivate(context: ExecutionContext): boolean {
try {
const request = context.switchToHttp().getRequest<Request>();
const cloudflareWebhookSecret = this.environmentService.get(
const cloudflareWebhookSecret = this.twentyConfigService.get(
'CLOUDFLARE_WEBHOOK_SECRET',
);

View File

@ -2,25 +2,25 @@ import { ExecutionContext } from '@nestjs/common';
import * as crypto from 'crypto';
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
import { CloudflareSecretMatchGuard } from './cloudflare-secret.guard';
describe('CloudflareSecretMatchGuard.canActivate', () => {
let guard: CloudflareSecretMatchGuard;
let environmentService: EnvironmentService;
let twentyConfigService: TwentyConfigService;
beforeEach(() => {
environmentService = {
twentyConfigService = {
get: jest.fn(),
} as unknown as EnvironmentService;
guard = new CloudflareSecretMatchGuard(environmentService);
} as unknown as TwentyConfigService;
guard = new CloudflareSecretMatchGuard(twentyConfigService);
});
it('should return true when the webhook secret matches', () => {
const mockRequest = { headers: { 'cf-webhook-auth': 'valid-secret' } };
jest.spyOn(environmentService, 'get').mockReturnValue('valid-secret');
jest.spyOn(twentyConfigService, 'get').mockReturnValue('valid-secret');
const mockContext = {
switchToHttp: () => ({
@ -36,7 +36,7 @@ describe('CloudflareSecretMatchGuard.canActivate', () => {
it('should return true when env is not set', () => {
const mockRequest = { headers: { 'cf-webhook-auth': 'valid-secret' } };
jest.spyOn(environmentService, 'get').mockReturnValue(undefined);
jest.spyOn(twentyConfigService, 'get').mockReturnValue(undefined);
const mockContext = {
switchToHttp: () => ({
@ -52,7 +52,7 @@ describe('CloudflareSecretMatchGuard.canActivate', () => {
it('should return false if an error occurs', () => {
const mockRequest = { headers: {} };
jest.spyOn(environmentService, 'get').mockReturnValue('valid-secret');
jest.spyOn(twentyConfigService, 'get').mockReturnValue('valid-secret');
const mockContext = {
switchToHttp: () => ({

View File

@ -1,18 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { CustomHostnameCreateResponse } from 'cloudflare/resources/custom-hostnames/custom-hostnames';
import Cloudflare from 'cloudflare';
import { CustomHostnameCreateResponse } from 'cloudflare/resources/custom-hostnames/custom-hostnames';
import { DomainManagerException } from 'src/engine/core-modules/domain-manager/domain-manager.exception';
import { CustomDomainService } from 'src/engine/core-modules/domain-manager/services/custom-domain.service';
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/services/domain-manager.service';
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
import { DomainManagerException } from 'src/engine/core-modules/domain-manager/domain-manager.exception';
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
jest.mock('cloudflare');
describe('CustomDomainService', () => {
let customDomainService: CustomDomainService;
let environmentService: EnvironmentService;
let twentyConfigService: TwentyConfigService;
let domainManagerService: DomainManagerService;
beforeEach(async () => {
@ -20,7 +20,7 @@ describe('CustomDomainService', () => {
providers: [
CustomDomainService,
{
provide: EnvironmentService,
provide: TwentyConfigService,
useValue: {
get: jest.fn(),
},
@ -35,7 +35,7 @@ describe('CustomDomainService', () => {
}).compile();
customDomainService = module.get<CustomDomainService>(CustomDomainService);
environmentService = module.get<EnvironmentService>(EnvironmentService);
twentyConfigService = module.get<TwentyConfigService>(TwentyConfigService);
domainManagerService =
module.get<DomainManagerService>(DomainManagerService);
@ -52,11 +52,11 @@ describe('CustomDomainService', () => {
it('should initialize cloudflareClient when CLOUDFLARE_API_KEY is defined', () => {
const mockApiKey = 'test-api-key';
jest.spyOn(environmentService, 'get').mockReturnValue(mockApiKey);
jest.spyOn(twentyConfigService, 'get').mockReturnValue(mockApiKey);
const instance = new CustomDomainService(environmentService, {} as any);
const instance = new CustomDomainService(twentyConfigService, {} as any);
expect(environmentService.get).toHaveBeenCalledWith('CLOUDFLARE_API_KEY');
expect(twentyConfigService.get).toHaveBeenCalledWith('CLOUDFLARE_API_KEY');
expect(Cloudflare).toHaveBeenCalledWith({ apiToken: mockApiKey });
expect(instance.cloudflareClient).toBeDefined();
});
@ -89,7 +89,7 @@ describe('CustomDomainService', () => {
jest
.spyOn(customDomainService, 'getCustomDomainDetails')
.mockResolvedValueOnce(undefined);
jest.spyOn(environmentService, 'get').mockReturnValue('test-zone-id');
jest.spyOn(twentyConfigService, 'get').mockReturnValue('test-zone-id');
(customDomainService as any).cloudflareClient = cloudflareMock;
await customDomainService.registerCustomDomain(customDomain);
@ -111,7 +111,7 @@ describe('CustomDomainService', () => {
},
};
jest.spyOn(environmentService, 'get').mockReturnValue('test-zone-id');
jest.spyOn(twentyConfigService, 'get').mockReturnValue('test-zone-id');
(customDomainService as any).cloudflareClient = cloudflareMock;
const result =
@ -137,7 +137,7 @@ describe('CustomDomainService', () => {
},
};
jest.spyOn(environmentService, 'get').mockReturnValue('test-zone-id');
jest.spyOn(twentyConfigService, 'get').mockReturnValue('test-zone-id');
jest
.spyOn(domainManagerService, 'getFrontUrl')
@ -175,7 +175,7 @@ describe('CustomDomainService', () => {
},
};
jest.spyOn(environmentService, 'get').mockReturnValue('test-zone-id');
jest.spyOn(twentyConfigService, 'get').mockReturnValue('test-zone-id');
jest
.spyOn(domainManagerService, 'getFrontUrl')
.mockReturnValue(new URL('https://front.domain'));
@ -199,7 +199,7 @@ describe('CustomDomainService', () => {
},
};
jest.spyOn(environmentService, 'get').mockReturnValue('test-zone-id');
jest.spyOn(twentyConfigService, 'get').mockReturnValue('test-zone-id');
(customDomainService as any).cloudflareClient = cloudflareMock;
await expect(
@ -249,7 +249,7 @@ describe('CustomDomainService', () => {
},
};
jest.spyOn(environmentService, 'get').mockReturnValue('test-zone-id');
jest.spyOn(twentyConfigService, 'get').mockReturnValue('test-zone-id');
(customDomainService as any).cloudflareClient = cloudflareMock;
await expect(

View File

@ -9,21 +9,21 @@ import {
DomainManagerExceptionCode,
} from 'src/engine/core-modules/domain-manager/domain-manager.exception';
import { CustomDomainValidRecords } from 'src/engine/core-modules/domain-manager/dtos/custom-domain-valid-records';
import { domainManagerValidator } from 'src/engine/core-modules/domain-manager/validator/cloudflare.validate';
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/services/domain-manager.service';
import { domainManagerValidator } from 'src/engine/core-modules/domain-manager/validator/cloudflare.validate';
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
@Injectable()
export class CustomDomainService {
cloudflareClient?: Cloudflare;
constructor(
private readonly environmentService: EnvironmentService,
private readonly twentyConfigService: TwentyConfigService,
private readonly domainManagerService: DomainManagerService,
) {
if (this.environmentService.get('CLOUDFLARE_API_KEY')) {
if (this.twentyConfigService.get('CLOUDFLARE_API_KEY')) {
this.cloudflareClient = new Cloudflare({
apiToken: this.environmentService.get('CLOUDFLARE_API_KEY'),
apiToken: this.twentyConfigService.get('CLOUDFLARE_API_KEY'),
});
}
}
@ -39,7 +39,7 @@ export class CustomDomainService {
}
return await this.cloudflareClient.customHostnames.create({
zone_id: this.environmentService.get('CLOUDFLARE_ZONE_ID'),
zone_id: this.twentyConfigService.get('CLOUDFLARE_ZONE_ID'),
hostname: customDomain,
ssl: {
method: 'txt',
@ -63,7 +63,7 @@ export class CustomDomainService {
domainManagerValidator.isCloudflareInstanceDefined(this.cloudflareClient);
const response = await this.cloudflareClient.customHostnames.list({
zone_id: this.environmentService.get('CLOUDFLARE_ZONE_ID'),
zone_id: this.twentyConfigService.get('CLOUDFLARE_ZONE_ID'),
hostname: customDomain,
});
@ -163,7 +163,7 @@ export class CustomDomainService {
if (customHostname) {
await this.cloudflareClient.customHostnames.delete(customHostname.id, {
zone_id: this.environmentService.get('CLOUDFLARE_ZONE_ID'),
zone_id: this.twentyConfigService.get('CLOUDFLARE_ZONE_ID'),
});
}
} catch (err) {
@ -175,7 +175,7 @@ export class CustomDomainService {
domainManagerValidator.isCloudflareInstanceDefined(this.cloudflareClient);
await this.cloudflareClient.customHostnames.delete(customHostnameId, {
zone_id: this.environmentService.get('CLOUDFLARE_ZONE_ID'),
zone_id: this.twentyConfigService.get('CLOUDFLARE_ZONE_ID'),
});
}

View File

@ -3,7 +3,7 @@ import { getRepositoryToken } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { DomainManagerService } from './domain-manager.service';
@ -12,7 +12,7 @@ describe('DomainManagerService', () => {
describe('getWorkspaceUrls', () => {
it('should return a URL containing the correct customDomain if customDomain is provided', () => {
jest
.spyOn(environmentService, 'get')
.spyOn(twentyConfigService, 'get')
.mockImplementation((key: string) => {
const env = {
FRONTEND_URL: 'https://example.com',
@ -35,7 +35,7 @@ describe('DomainManagerService', () => {
it('should return a URL containing the correct subdomain if customDomain is not provided but subdomain is', () => {
jest
.spyOn(environmentService, 'get')
.spyOn(twentyConfigService, 'get')
.mockImplementation((key: string) => {
const env = {
FRONTEND_URL: 'https://example.com',
@ -58,7 +58,7 @@ describe('DomainManagerService', () => {
});
});
let domainManagerService: DomainManagerService;
let environmentService: EnvironmentService;
let twentyConfigService: TwentyConfigService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
@ -69,7 +69,7 @@ describe('DomainManagerService', () => {
useClass: Repository,
},
{
provide: EnvironmentService,
provide: TwentyConfigService,
useValue: {
get: jest.fn(),
},
@ -79,13 +79,13 @@ describe('DomainManagerService', () => {
domainManagerService =
module.get<DomainManagerService>(DomainManagerService);
environmentService = module.get<EnvironmentService>(EnvironmentService);
twentyConfigService = module.get<TwentyConfigService>(TwentyConfigService);
});
describe('buildBaseUrl', () => {
it('should build the base URL from environment variables', () => {
jest
.spyOn(environmentService, 'get')
.spyOn(twentyConfigService, 'get')
.mockImplementation((key: string) => {
const env = {
FRONTEND_URL: 'https://example.com',
@ -101,7 +101,7 @@ describe('DomainManagerService', () => {
it('should append default subdomain if multiworkspace is enabled', () => {
jest
.spyOn(environmentService, 'get')
.spyOn(twentyConfigService, 'get')
.mockImplementation((key: string) => {
const env = {
FRONTEND_URL: 'https://example.com',
@ -121,7 +121,7 @@ describe('DomainManagerService', () => {
describe('buildWorkspaceURL', () => {
it('should build workspace URL with given subdomain', () => {
jest
.spyOn(environmentService, 'get')
.spyOn(twentyConfigService, 'get')
.mockImplementation((key: string) => {
const env = {
FRONTEND_URL: 'https://example.com',
@ -145,7 +145,7 @@ describe('DomainManagerService', () => {
it('should set the pathname if provided', () => {
jest
.spyOn(environmentService, 'get')
.spyOn(twentyConfigService, 'get')
.mockImplementation((key: string) => {
const env = {
FRONTEND_URL: 'https://example.com',
@ -168,7 +168,7 @@ describe('DomainManagerService', () => {
it('should set the search parameters if provided', () => {
jest
.spyOn(environmentService, 'get')
.spyOn(twentyConfigService, 'get')
.mockImplementation((key: string) => {
const env = {
FRONTEND_URL: 'https://example.com',

View File

@ -10,7 +10,7 @@ import { CustomDomainValidRecords } from 'src/engine/core-modules/domain-manager
import { generateRandomSubdomain } from 'src/engine/core-modules/domain-manager/utils/generate-random-subdomain';
import { getSubdomainFromEmail } from 'src/engine/core-modules/domain-manager/utils/get-subdomain-from-email';
import { getSubdomainNameFromDisplayName } from 'src/engine/core-modules/domain-manager/utils/get-subdomain-name-from-display-name';
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.validate';
@ -19,13 +19,13 @@ export class DomainManagerService {
constructor(
@InjectRepository(Workspace, 'core')
private readonly workspaceRepository: Repository<Workspace>,
private readonly environmentService: EnvironmentService,
private readonly twentyConfigService: TwentyConfigService,
) {}
getFrontUrl() {
return new URL(
this.environmentService.get('FRONTEND_URL') ??
this.environmentService.get('SERVER_URL'),
this.twentyConfigService.get('FRONTEND_URL') ??
this.twentyConfigService.get('SERVER_URL'),
);
}
@ -33,10 +33,10 @@ export class DomainManagerService {
const baseUrl = this.getFrontUrl();
if (
this.environmentService.get('IS_MULTIWORKSPACE_ENABLED') &&
this.environmentService.get('DEFAULT_SUBDOMAIN')
this.twentyConfigService.get('IS_MULTIWORKSPACE_ENABLED') &&
this.twentyConfigService.get('DEFAULT_SUBDOMAIN')
) {
baseUrl.hostname = `${this.environmentService.get('DEFAULT_SUBDOMAIN')}.${baseUrl.hostname}`;
baseUrl.hostname = `${this.twentyConfigService.get('DEFAULT_SUBDOMAIN')}.${baseUrl.hostname}`;
}
return baseUrl;
@ -122,7 +122,7 @@ export class DomainManagerService {
}
isDefaultSubdomain(subdomain: string) {
return subdomain === this.environmentService.get('DEFAULT_SUBDOMAIN');
return subdomain === this.twentyConfigService.get('DEFAULT_SUBDOMAIN');
}
computeRedirectErrorUrl(
@ -139,7 +139,7 @@ export class DomainManagerService {
}
private async getDefaultWorkspace() {
if (this.environmentService.get('IS_MULTIWORKSPACE_ENABLED')) {
if (this.twentyConfigService.get('IS_MULTIWORKSPACE_ENABLED')) {
throw new Error(
'Default workspace does not exist when multi-workspace is enabled',
);
@ -171,7 +171,7 @@ export class DomainManagerService {
}
async getWorkspaceByOriginOrDefaultWorkspace(origin: string) {
if (!this.environmentService.get('IS_MULTIWORKSPACE_ENABLED')) {
if (!this.twentyConfigService.get('IS_MULTIWORKSPACE_ENABLED')) {
return this.getDefaultWorkspace();
}
@ -222,7 +222,7 @@ export class DomainManagerService {
private getTwentyWorkspaceUrl(subdomain: string) {
const url = this.getFrontUrl();
url.hostname = this.environmentService.get('IS_MULTIWORKSPACE_ENABLED')
url.hostname = this.twentyConfigService.get('IS_MULTIWORKSPACE_ENABLED')
? `${subdomain}.${url.hostname}`
: url.hostname;
@ -234,7 +234,7 @@ export class DomainManagerService {
) {
if (!workspace) {
return {
subdomain: this.environmentService.get('DEFAULT_SUBDOMAIN'),
subdomain: this.twentyConfigService.get('DEFAULT_SUBDOMAIN'),
customDomain: null,
};
}