Environment variables in admin panel (read only) - front (#10011)
Frontend for https://github.com/twentyhq/core-team-issues/issues/293 POC - https://github.com/twentyhq/twenty/pull/9903 --------- Co-authored-by: Félix Malfait <felix@twenty.com> Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
This commit is contained in:
@ -33,9 +33,33 @@ jest.mock(
|
||||
);
|
||||
|
||||
jest.mock(
|
||||
'src/engine/core-modules/environment/constants/environment-variables-hidden-groups',
|
||||
'src/engine/core-modules/environment/constants/environment-variables-group-metadata',
|
||||
() => ({
|
||||
ENVIRONMENT_VARIABLES_HIDDEN_GROUPS: new Set(['HIDDEN_GROUP']),
|
||||
ENVIRONMENT_VARIABLES_GROUP_METADATA: {
|
||||
GROUP_1: {
|
||||
position: 100,
|
||||
description: '',
|
||||
},
|
||||
GROUP_2: {
|
||||
position: 200,
|
||||
description: '',
|
||||
},
|
||||
VISIBLE_GROUP: {
|
||||
position: 300,
|
||||
description: '',
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
jest.mock(
|
||||
'src/engine/core-modules/environment/constants/environment-variables-sub-group-metadata',
|
||||
() => ({
|
||||
ENVIRONMENT_VARIABLES_SUB_GROUP_METADATA: {
|
||||
SUBGROUP_1: {
|
||||
description: '',
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
@ -262,9 +286,10 @@ describe('AdminPanelService', () => {
|
||||
const result = service.getEnvironmentVariablesGrouped();
|
||||
|
||||
expect(result).toEqual({
|
||||
groups: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
groupName: 'GROUP_1',
|
||||
groups: [
|
||||
{
|
||||
name: 'GROUP_1',
|
||||
description: '',
|
||||
variables: [
|
||||
{
|
||||
name: 'VAR_1',
|
||||
@ -275,7 +300,8 @@ describe('AdminPanelService', () => {
|
||||
],
|
||||
subgroups: [
|
||||
{
|
||||
subgroupName: 'SUBGROUP_1',
|
||||
name: 'SUBGROUP_1',
|
||||
description: '',
|
||||
variables: [
|
||||
{
|
||||
name: 'VAR_2',
|
||||
@ -286,9 +312,10 @@ describe('AdminPanelService', () => {
|
||||
],
|
||||
},
|
||||
],
|
||||
}),
|
||||
expect.objectContaining({
|
||||
groupName: 'GROUP_2',
|
||||
},
|
||||
{
|
||||
name: 'GROUP_2',
|
||||
description: '',
|
||||
variables: [
|
||||
{
|
||||
name: 'VAR_3',
|
||||
@ -298,8 +325,8 @@ describe('AdminPanelService', () => {
|
||||
},
|
||||
],
|
||||
subgroups: [],
|
||||
}),
|
||||
]),
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
@ -324,7 +351,7 @@ describe('AdminPanelService', () => {
|
||||
const result = service.getEnvironmentVariablesGrouped();
|
||||
|
||||
const group = result.groups.find(
|
||||
(g) => g.groupName === ('GROUP_1' as EnvironmentVariablesGroup),
|
||||
(g) => g.name === ('GROUP_1' as EnvironmentVariablesGroup),
|
||||
);
|
||||
|
||||
expect(group?.variables[0].name).toBe('A_VAR');
|
||||
@ -340,34 +367,5 @@ describe('AdminPanelService', () => {
|
||||
groups: [],
|
||||
});
|
||||
});
|
||||
|
||||
it('should exclude hidden groups from the output', () => {
|
||||
EnvironmentServiceGetAllMock.mockReturnValue({
|
||||
VAR_1: {
|
||||
value: 'value1',
|
||||
metadata: {
|
||||
group: 'HIDDEN_GROUP',
|
||||
description: 'Description 1',
|
||||
},
|
||||
},
|
||||
VAR_2: {
|
||||
value: 'value2',
|
||||
metadata: {
|
||||
group: 'VISIBLE_GROUP',
|
||||
description: 'Description 2',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const result = service.getEnvironmentVariablesGrouped();
|
||||
|
||||
expect(result.groups).toHaveLength(1);
|
||||
expect(result.groups[0].groupName).toBe('VISIBLE_GROUP');
|
||||
expect(result.groups).not.toContainEqual(
|
||||
expect.objectContaining({
|
||||
groupName: 'HIDDEN_GROUP',
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -12,8 +12,8 @@ import {
|
||||
AuthExceptionCode,
|
||||
} from 'src/engine/core-modules/auth/auth.exception';
|
||||
import { LoginTokenService } from 'src/engine/core-modules/auth/token/services/login-token.service';
|
||||
import { ENVIRONMENT_VARIABLES_GROUP_POSITION } from 'src/engine/core-modules/environment/constants/environment-variables-group-position';
|
||||
import { ENVIRONMENT_VARIABLES_HIDDEN_GROUPS } from 'src/engine/core-modules/environment/constants/environment-variables-hidden-groups';
|
||||
import { ENVIRONMENT_VARIABLES_GROUP_METADATA } from 'src/engine/core-modules/environment/constants/environment-variables-group-metadata';
|
||||
import { ENVIRONMENT_VARIABLES_SUB_GROUP_METADATA } from 'src/engine/core-modules/environment/constants/environment-variables-sub-group-metadata';
|
||||
import { EnvironmentVariablesGroup } from 'src/engine/core-modules/environment/enums/environment-variables-group.enum';
|
||||
import { EnvironmentVariablesSubGroup } from 'src/engine/core-modules/environment/enums/environment-variables-sub-group.enum';
|
||||
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
||||
@ -180,10 +180,6 @@ export class AdminPanelService {
|
||||
for (const [varName, { value, metadata }] of Object.entries(rawEnvVars)) {
|
||||
const { group, subGroup, description } = metadata;
|
||||
|
||||
if (ENVIRONMENT_VARIABLES_HIDDEN_GROUPS.has(group)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const envVar: EnvironmentVariable = {
|
||||
name: varName,
|
||||
description,
|
||||
@ -218,18 +214,23 @@ export class AdminPanelService {
|
||||
groupedData.entries(),
|
||||
)
|
||||
.sort((a, b) => {
|
||||
const positionA = ENVIRONMENT_VARIABLES_GROUP_POSITION[a[0]];
|
||||
const positionB = ENVIRONMENT_VARIABLES_GROUP_POSITION[b[0]];
|
||||
const positionA = ENVIRONMENT_VARIABLES_GROUP_METADATA[a[0]].position;
|
||||
const positionB = ENVIRONMENT_VARIABLES_GROUP_METADATA[b[0]].position;
|
||||
|
||||
return positionA - positionB;
|
||||
})
|
||||
.map(([groupName, data]) => ({
|
||||
groupName,
|
||||
.map(([name, data]) => ({
|
||||
name,
|
||||
description: ENVIRONMENT_VARIABLES_GROUP_METADATA[name].description,
|
||||
isHiddenOnLoad:
|
||||
ENVIRONMENT_VARIABLES_GROUP_METADATA[name].isHiddenOnLoad,
|
||||
variables: data.variables.sort((a, b) => a.name.localeCompare(b.name)),
|
||||
subgroups: Array.from(data.subgroups.entries())
|
||||
.sort((a, b) => a[0].localeCompare(b[0]))
|
||||
.map(([subgroupName, variables]) => ({
|
||||
subgroupName,
|
||||
.map(([name, variables]) => ({
|
||||
name,
|
||||
description:
|
||||
ENVIRONMENT_VARIABLES_SUB_GROUP_METADATA[name].description,
|
||||
variables,
|
||||
})),
|
||||
}));
|
||||
|
||||
@ -18,5 +18,11 @@ export class EnvironmentVariablesGroupData {
|
||||
subgroups: EnvironmentVariablesSubgroupData[];
|
||||
|
||||
@Field(() => EnvironmentVariablesGroup)
|
||||
groupName: EnvironmentVariablesGroup;
|
||||
name: EnvironmentVariablesGroup;
|
||||
|
||||
@Field(() => String, { defaultValue: '' })
|
||||
description: string;
|
||||
|
||||
@Field(() => Boolean, { defaultValue: false })
|
||||
isHiddenOnLoad: boolean;
|
||||
}
|
||||
|
||||
@ -14,5 +14,8 @@ export class EnvironmentVariablesSubgroupData {
|
||||
variables: EnvironmentVariable[];
|
||||
|
||||
@Field(() => EnvironmentVariablesSubGroup)
|
||||
subgroupName: EnvironmentVariablesSubGroup;
|
||||
name: EnvironmentVariablesSubGroup;
|
||||
|
||||
@Field(() => String, { defaultValue: '' })
|
||||
description: string;
|
||||
}
|
||||
|
||||
@ -21,11 +21,11 @@ import { GoogleAPIsOauthRequestCodeGuard } from 'src/engine/core-modules/auth/gu
|
||||
import { GoogleAPIsService } from 'src/engine/core-modules/auth/services/google-apis.service';
|
||||
import { TransientTokenService } from 'src/engine/core-modules/auth/token/services/transient-token.service';
|
||||
import { GoogleAPIsRequest } from 'src/engine/core-modules/auth/types/google-api-request.type';
|
||||
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/services/domain-manager.service';
|
||||
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
||||
import { GuardRedirectService } from 'src/engine/core-modules/guard-redirect/services/guard-redirect.service';
|
||||
import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/services/domain-manager.service';
|
||||
import { GuardRedirectService } from 'src/engine/core-modules/guard-redirect/services/guard-redirect.service';
|
||||
|
||||
@Controller('auth/google-apis')
|
||||
@UseFilters(AuthRestApiExceptionFilter)
|
||||
@ -72,16 +72,6 @@ export class GoogleAPIsAuthController {
|
||||
const { workspaceMemberId, userId, workspaceId } =
|
||||
await this.transientTokenService.verifyTransientToken(transientToken);
|
||||
|
||||
const demoWorkspaceIds =
|
||||
this.environmentService.get('DEMO_WORKSPACE_IDS');
|
||||
|
||||
if (demoWorkspaceIds.includes(workspaceId)) {
|
||||
throw new AuthException(
|
||||
'Cannot connect Google account to demo workspace',
|
||||
AuthExceptionCode.FORBIDDEN_EXCEPTION,
|
||||
);
|
||||
}
|
||||
|
||||
if (!workspaceId) {
|
||||
throw new AuthException(
|
||||
'Workspace not found',
|
||||
|
||||
@ -23,9 +23,9 @@ import { TransientTokenService } from 'src/engine/core-modules/auth/token/servic
|
||||
import { MicrosoftAPIsRequest } from 'src/engine/core-modules/auth/types/microsoft-api-request.type';
|
||||
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/services/domain-manager.service';
|
||||
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
||||
import { GuardRedirectService } from 'src/engine/core-modules/guard-redirect/services/guard-redirect.service';
|
||||
import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { GuardRedirectService } from 'src/engine/core-modules/guard-redirect/services/guard-redirect.service';
|
||||
|
||||
@Controller('auth/microsoft-apis')
|
||||
@UseFilters(AuthRestApiExceptionFilter)
|
||||
@ -72,16 +72,6 @@ export class MicrosoftAPIsAuthController {
|
||||
const { workspaceMemberId, userId, workspaceId } =
|
||||
await this.transientTokenService.verifyTransientToken(transientToken);
|
||||
|
||||
const demoWorkspaceIds =
|
||||
this.environmentService.get('DEMO_WORKSPACE_IDS');
|
||||
|
||||
if (demoWorkspaceIds.includes(workspaceId)) {
|
||||
throw new AuthException(
|
||||
'Cannot connect Microsoft account to demo workspace',
|
||||
AuthExceptionCode.FORBIDDEN_EXCEPTION,
|
||||
);
|
||||
}
|
||||
|
||||
if (!workspaceId) {
|
||||
throw new AuthException(
|
||||
'Workspace not found',
|
||||
|
||||
@ -1,24 +1,26 @@
|
||||
import { ENVIRONMENT_VARIABLES_GROUP_POSITION } from 'src/engine/core-modules/environment/constants/environment-variables-group-position';
|
||||
import { ENVIRONMENT_VARIABLES_GROUP_METADATA } from 'src/engine/core-modules/environment/constants/environment-variables-group-metadata';
|
||||
import { EnvironmentVariablesGroup } from 'src/engine/core-modules/environment/enums/environment-variables-group.enum';
|
||||
|
||||
describe('ENVIRONMENT_VARIABLES_GROUP_POSITION', () => {
|
||||
describe('ENVIRONMENT_VARIABLES_GROUP_METADATA', () => {
|
||||
it('should include all EnvironmentVariablesGroup enum values', () => {
|
||||
const enumValues = Object.values(EnvironmentVariablesGroup);
|
||||
const positionKeys = Object.keys(ENVIRONMENT_VARIABLES_GROUP_POSITION);
|
||||
const metadataKeys = Object.keys(ENVIRONMENT_VARIABLES_GROUP_METADATA);
|
||||
|
||||
enumValues.forEach((enumValue) => {
|
||||
expect(positionKeys).toContain(enumValue);
|
||||
expect(metadataKeys).toContain(enumValue);
|
||||
});
|
||||
|
||||
positionKeys.forEach((key) => {
|
||||
metadataKeys.forEach((key) => {
|
||||
expect(enumValues).toContain(key);
|
||||
});
|
||||
|
||||
expect(enumValues.length).toBe(positionKeys.length);
|
||||
expect(enumValues.length).toBe(metadataKeys.length);
|
||||
});
|
||||
|
||||
it('should have unique position values', () => {
|
||||
const positions = Object.values(ENVIRONMENT_VARIABLES_GROUP_POSITION);
|
||||
const positions = Object.values(ENVIRONMENT_VARIABLES_GROUP_METADATA).map(
|
||||
(metadata) => metadata.position,
|
||||
);
|
||||
const uniquePositions = new Set(positions);
|
||||
|
||||
expect(positions.length).toBe(uniquePositions.size);
|
||||
@ -0,0 +1,44 @@
|
||||
import { EnvironmentVariablesGroup } from 'src/engine/core-modules/environment/enums/environment-variables-group.enum';
|
||||
|
||||
type GroupMetadata = {
|
||||
position: number;
|
||||
description: string;
|
||||
isHiddenOnLoad: boolean;
|
||||
};
|
||||
|
||||
export const ENVIRONMENT_VARIABLES_GROUP_METADATA: Record<
|
||||
EnvironmentVariablesGroup,
|
||||
GroupMetadata
|
||||
> = {
|
||||
[EnvironmentVariablesGroup.ServerConfig]: {
|
||||
position: 100,
|
||||
description: '',
|
||||
isHiddenOnLoad: false,
|
||||
},
|
||||
[EnvironmentVariablesGroup.Authentication]: {
|
||||
position: 400,
|
||||
description: '',
|
||||
isHiddenOnLoad: false,
|
||||
},
|
||||
[EnvironmentVariablesGroup.Email]: {
|
||||
position: 800,
|
||||
description: '',
|
||||
isHiddenOnLoad: false,
|
||||
},
|
||||
[EnvironmentVariablesGroup.Workspace]: {
|
||||
position: 1000,
|
||||
description: '',
|
||||
isHiddenOnLoad: false,
|
||||
},
|
||||
[EnvironmentVariablesGroup.Logging]: {
|
||||
position: 1200,
|
||||
description: '',
|
||||
isHiddenOnLoad: false,
|
||||
},
|
||||
[EnvironmentVariablesGroup.Other]: {
|
||||
position: 1700,
|
||||
description:
|
||||
"The variables in this section are mostly used for internal purposes (running our Cloud offering), but shouldn't usually be required for a simple self-hosted instance",
|
||||
isHiddenOnLoad: true,
|
||||
},
|
||||
};
|
||||
@ -1,23 +1,31 @@
|
||||
import { EnvironmentVariablesGroup } from 'src/engine/core-modules/environment/enums/environment-variables-group.enum';
|
||||
|
||||
export const ENVIRONMENT_VARIABLES_GROUP_POSITION: Record<
|
||||
export const ENVIRONMENT_VARIABLES_GROUP_METADATA: Record<
|
||||
EnvironmentVariablesGroup,
|
||||
number
|
||||
{ position: number; description: string }
|
||||
> = {
|
||||
[EnvironmentVariablesGroup.ServerConfig]: 100,
|
||||
[EnvironmentVariablesGroup.Database]: 200,
|
||||
[EnvironmentVariablesGroup.Security]: 300,
|
||||
[EnvironmentVariablesGroup.Authentication]: 400,
|
||||
[EnvironmentVariablesGroup.Cache]: 500,
|
||||
[EnvironmentVariablesGroup.QueueConfig]: 600,
|
||||
[EnvironmentVariablesGroup.Storage]: 700,
|
||||
[EnvironmentVariablesGroup.Email]: 800,
|
||||
[EnvironmentVariablesGroup.Frontend]: 900,
|
||||
[EnvironmentVariablesGroup.Workspace]: 1000,
|
||||
[EnvironmentVariablesGroup.Analytics]: 1100,
|
||||
[EnvironmentVariablesGroup.Logging]: 1200,
|
||||
[EnvironmentVariablesGroup.Billing]: 1300,
|
||||
[EnvironmentVariablesGroup.Support]: 1400,
|
||||
[EnvironmentVariablesGroup.LLM]: 1500,
|
||||
[EnvironmentVariablesGroup.Serverless]: 1600,
|
||||
[EnvironmentVariablesGroup.ServerConfig]: {
|
||||
position: 100,
|
||||
description: '',
|
||||
},
|
||||
[EnvironmentVariablesGroup.Authentication]: {
|
||||
position: 400,
|
||||
description: '',
|
||||
},
|
||||
[EnvironmentVariablesGroup.Email]: {
|
||||
position: 800,
|
||||
description: '',
|
||||
},
|
||||
[EnvironmentVariablesGroup.Workspace]: {
|
||||
position: 1000,
|
||||
description: '',
|
||||
},
|
||||
[EnvironmentVariablesGroup.Logging]: {
|
||||
position: 1200,
|
||||
description: '',
|
||||
},
|
||||
[EnvironmentVariablesGroup.Other]: {
|
||||
position: 1700,
|
||||
description: '',
|
||||
},
|
||||
};
|
||||
|
||||
@ -1,4 +0,0 @@
|
||||
import { EnvironmentVariablesGroup } from 'src/engine/core-modules/environment/enums/environment-variables-group.enum';
|
||||
|
||||
export const ENVIRONMENT_VARIABLES_HIDDEN_GROUPS: Set<EnvironmentVariablesGroup> =
|
||||
new Set([EnvironmentVariablesGroup.LLM]);
|
||||
@ -0,0 +1,71 @@
|
||||
import { EnvironmentVariablesSubGroup } from 'src/engine/core-modules/environment/enums/environment-variables-sub-group.enum';
|
||||
|
||||
type SubGroupMetadata = {
|
||||
description: string;
|
||||
};
|
||||
|
||||
export const ENVIRONMENT_VARIABLES_SUB_GROUP_METADATA: Record<
|
||||
EnvironmentVariablesSubGroup,
|
||||
SubGroupMetadata
|
||||
> = {
|
||||
[EnvironmentVariablesSubGroup.PasswordAuth]: {
|
||||
description: '',
|
||||
},
|
||||
[EnvironmentVariablesSubGroup.GoogleAuth]: {
|
||||
description: 'Configure Google integration (login, calendar, email)',
|
||||
},
|
||||
[EnvironmentVariablesSubGroup.MicrosoftAuth]: {
|
||||
description: 'Configure Microsoft integration (login, calendar, email)',
|
||||
},
|
||||
[EnvironmentVariablesSubGroup.EmailSettings]: {
|
||||
description:
|
||||
'This is used for emails that are sent by the app such as invitations to join a workspace. This is not used to email CRM contacts.',
|
||||
},
|
||||
[EnvironmentVariablesSubGroup.StorageConfig]: {
|
||||
description:
|
||||
"By default, file uploads are stored on the local filesystem, which is suitable for traditional servers. However, for ephemeral deployment servers, it's essential to configure the variables here to set up an S3-compatible file system. This ensures that files remain unaffected by server redeploys.",
|
||||
},
|
||||
[EnvironmentVariablesSubGroup.TokensDuration]: {
|
||||
description:
|
||||
"These have been set to sensible default so you probably don't need to change them unless you have a specific use-case.",
|
||||
},
|
||||
[EnvironmentVariablesSubGroup.SSL]: {
|
||||
description:
|
||||
'Configure this if you want to setup SSL on your server or full end-to-end encryption. If you just want basic HTTPS, a simple setup like Cloudflare in flexible mode might be easier.',
|
||||
},
|
||||
[EnvironmentVariablesSubGroup.RateLimiting]: {
|
||||
description:
|
||||
'We use this to limit the number of requests to the server. This is useful to prevent abuse.',
|
||||
},
|
||||
[EnvironmentVariablesSubGroup.TinybirdConfig]: {
|
||||
description:
|
||||
"We're running a test to perform analytics within the app. This will evolve.",
|
||||
},
|
||||
[EnvironmentVariablesSubGroup.BillingConfig]: {
|
||||
description:
|
||||
'We use Stripe in our Cloud app to charge customers. Not relevant to Self-hosters.',
|
||||
},
|
||||
[EnvironmentVariablesSubGroup.ExceptionHandler]: {
|
||||
description:
|
||||
'By default, exceptions are sent to the logs. This should be enough for most self-hosting use-cases. For our cloud app we use Sentry.',
|
||||
},
|
||||
[EnvironmentVariablesSubGroup.SupportChatConfig]: {
|
||||
description:
|
||||
'We use this to setup a small support chat on the bottom left. Currently powered by Front.',
|
||||
},
|
||||
[EnvironmentVariablesSubGroup.CloudflareConfig]: {
|
||||
description: '',
|
||||
},
|
||||
[EnvironmentVariablesSubGroup.CaptchaConfig]: {
|
||||
description:
|
||||
'This protects critical endpoints like login and signup with a captcha to prevent bot attacks. Likely unnecessary for self-hosting scenarios.',
|
||||
},
|
||||
[EnvironmentVariablesSubGroup.ServerlessConfig]: {
|
||||
description:
|
||||
'In our multi-tenant cloud app, we offload untrusted custom code from workflows to a serverless system (Lambda) for enhanced security and scalability. Self-hosters with a single tenant can typically ignore this configuration.',
|
||||
},
|
||||
[EnvironmentVariablesSubGroup.LLM]: {
|
||||
description:
|
||||
'Configure the LLM provider and model to use for the app. This is experimental and not linked to any public feature.',
|
||||
},
|
||||
};
|
||||
@ -1,18 +1,8 @@
|
||||
export enum EnvironmentVariablesGroup {
|
||||
Authentication = 'authentication',
|
||||
Email = 'email',
|
||||
Database = 'database',
|
||||
Storage = 'storage',
|
||||
ServerConfig = 'server-config',
|
||||
QueueConfig = 'queue-config',
|
||||
Logging = 'logging',
|
||||
Cache = 'cache',
|
||||
Analytics = 'analytics',
|
||||
Billing = 'billing',
|
||||
Frontend = 'frontend',
|
||||
Security = 'security',
|
||||
Serverless = 'serverless',
|
||||
Support = 'support',
|
||||
LLM = 'llm',
|
||||
Workspace = 'workspace',
|
||||
Other = 'other',
|
||||
}
|
||||
|
||||
@ -2,16 +2,17 @@ export enum EnvironmentVariablesSubGroup {
|
||||
PasswordAuth = 'password-auth',
|
||||
GoogleAuth = 'google-auth',
|
||||
MicrosoftAuth = 'microsoft-auth',
|
||||
SmtpConfig = 'smtp-config',
|
||||
EmailSettings = 'email-settings',
|
||||
S3Config = 's3-config',
|
||||
Tokens = 'tokens',
|
||||
StorageConfig = 'storage-config',
|
||||
TokensDuration = 'tokens-duration',
|
||||
SSL = 'ssl',
|
||||
RateLimiting = 'rate-limiting',
|
||||
LambdaConfig = 'lambda-config',
|
||||
TinybirdConfig = 'tinybird-config',
|
||||
StripeConfig = 'stripe-config',
|
||||
SentryConfig = 'sentry-config',
|
||||
FrontSupportConfig = 'front-support-config',
|
||||
BillingConfig = 'billing-config',
|
||||
ExceptionHandler = 'exception-handler',
|
||||
SupportChatConfig = 'support-chat-config',
|
||||
CloudflareConfig = 'cloudflare-config',
|
||||
CaptchaConfig = 'captcha-config',
|
||||
ServerlessConfig = 'serverless-config',
|
||||
LLM = 'llm',
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -86,26 +86,5 @@ describe('EnvironmentService', () => {
|
||||
expect(result.APP_SECRET.value).not.toBe('super-secret-value');
|
||||
expect(result.APP_SECRET.value).toMatch(/^\*+[a-zA-Z0-9]{5}$/);
|
||||
});
|
||||
|
||||
it('should use default value when environment variable is not set', () => {
|
||||
const mockMetadata = {
|
||||
DEBUG_PORT: {
|
||||
title: 'Debug Port',
|
||||
description: 'Debug port number',
|
||||
},
|
||||
};
|
||||
|
||||
Reflect.defineMetadata(
|
||||
'environment-variables',
|
||||
mockMetadata,
|
||||
EnvironmentVariables,
|
||||
);
|
||||
|
||||
jest.spyOn(configService, 'get').mockReturnValue(undefined);
|
||||
|
||||
const result = service.getAll();
|
||||
|
||||
expect(result.DEBUG_PORT.value).toBe(9000);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -8,11 +8,10 @@ import { FileFolder } from 'src/engine/core-modules/file/interfaces/file-folder.
|
||||
import { FileUploadService } from 'src/engine/core-modules/file/file-upload/services/file-upload.service';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
|
||||
import { DemoEnvGuard } from 'src/engine/guards/demo.env.guard';
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
import { streamToBuffer } from 'src/utils/stream-to-buffer';
|
||||
|
||||
@UseGuards(WorkspaceAuthGuard, DemoEnvGuard)
|
||||
@UseGuards(WorkspaceAuthGuard)
|
||||
@Resolver()
|
||||
export class FileUploadResolver {
|
||||
constructor(private readonly fileUploadService: FileUploadService) {}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { OnModuleDestroy } from '@nestjs/common';
|
||||
|
||||
import { JobsOptions, Queue, QueueOptions, Worker } from 'bullmq';
|
||||
import { v4 } from 'uuid';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import {
|
||||
QueueCronJobOptions,
|
||||
|
||||
@ -46,7 +46,6 @@ import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.
|
||||
import { AuthUser } from 'src/engine/decorators/auth/auth-user.decorator';
|
||||
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
|
||||
import { OriginHeader } from 'src/engine/decorators/auth/origin-header.decorator';
|
||||
import { DemoEnvGuard } from 'src/engine/guards/demo.env.guard';
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
import { RoleDTO } from 'src/engine/metadata-modules/role/dtos/role.dto';
|
||||
import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role.service';
|
||||
@ -295,7 +294,6 @@ export class UserResolver {
|
||||
return `${paths[0]}?token=${fileToken}`;
|
||||
}
|
||||
|
||||
@UseGuards(DemoEnvGuard)
|
||||
@Mutation(() => User)
|
||||
async deleteUser(@AuthUser() { id: userId }: User) {
|
||||
// Proceed with user deletion
|
||||
|
||||
@ -10,8 +10,8 @@ import {
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { FileUpload, GraphQLUpload } from 'graphql-upload';
|
||||
import { Repository } from 'typeorm';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { FileFolder } from 'src/engine/core-modules/file/interfaces/file-folder.interface';
|
||||
|
||||
@ -39,7 +39,6 @@ import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.
|
||||
import { AuthUser } from 'src/engine/decorators/auth/auth-user.decorator';
|
||||
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
|
||||
import { OriginHeader } from 'src/engine/decorators/auth/origin-header.decorator';
|
||||
import { DemoEnvGuard } from 'src/engine/guards/demo.env.guard';
|
||||
import { UserAuthGuard } from 'src/engine/guards/user-auth.guard';
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
import { GraphqlValidationExceptionFilter } from 'src/filters/graphql-validation-exception.filter';
|
||||
@ -151,7 +150,7 @@ export class WorkspaceResolver {
|
||||
}
|
||||
|
||||
@Mutation(() => Workspace)
|
||||
@UseGuards(DemoEnvGuard, WorkspaceAuthGuard)
|
||||
@UseGuards(WorkspaceAuthGuard)
|
||||
async deleteCurrentWorkspace(@AuthWorkspace() { id }: Workspace) {
|
||||
return this.workspaceService.deleteWorkspace(id);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user