refactor(core): Port workflows config (no-changelog) (#10173)

This commit is contained in:
Iván Ovejero 2024-07-24 14:38:29 +02:00 committed by GitHub
parent 9056242b3a
commit b81f0bf9ea
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 48 additions and 28 deletions

View file

@ -0,0 +1,20 @@
import { Config, Env } from '../decorators';
@Config
export class WorkflowsConfig {
/** Default name for workflow */
@Env('WORKFLOWS_DEFAULT_NAME')
readonly defaultName: string = 'My workflow';
/** Show onboarding flow in new workflow */
@Env('N8N_ONBOARDING_FLOW_DISABLED')
readonly onboardingFlowDisabled: boolean = false;
/** Default option for which workflows may call the current workflow */
@Env('N8N_WORKFLOW_CALLER_POLICY_DEFAULT_OPTION')
readonly callerPolicyDefaultOption:
| 'any'
| 'none'
| 'workflowsFromAList'
| 'workflowsFromSameOwner' = 'workflowsFromSameOwner';
}

View file

@ -9,6 +9,7 @@ import { TemplatesConfig } from './configs/templates';
import { EventBusConfig } from './configs/event-bus';
import { NodesConfig } from './configs/nodes';
import { ExternalStorageConfig } from './configs/external-storage';
import { WorkflowsConfig } from './configs/workflows';
@Config
class UserManagementConfig {
@ -47,4 +48,7 @@ export class GlobalConfig {
@Nested
readonly externalStorage: ExternalStorageConfig;
@Nested
readonly workflows: WorkflowsConfig;
}

View file

@ -135,6 +135,11 @@ describe('GlobalConfig', () => {
},
},
},
workflows: {
defaultName: 'My workflow',
onboardingFlowDisabled: false,
callerPolicyDefaultOption: 'workflowsFromSameOwner',
},
};
it('should use all default values when no env variables are defined', () => {

View file

@ -12,27 +12,6 @@ convict.addFormat({
});
export const schema = {
workflows: {
defaultName: {
doc: 'Default name for workflow',
format: String,
default: 'My workflow',
env: 'WORKFLOWS_DEFAULT_NAME',
},
onboardingFlowDisabled: {
doc: 'Show onboarding flow in new workflow',
format: Boolean,
default: false,
env: 'N8N_ONBOARDING_FLOW_DISABLED',
},
callerPolicyDefaultOption: {
doc: 'Default option for which workflows may call the current workflow',
format: ['any', 'none', 'workflowsFromAList', 'workflowsFromSameOwner'] as const,
default: 'workflowsFromSameOwner',
env: 'N8N_WORKFLOW_CALLER_POLICY_DEFAULT_OPTION',
},
},
executions: {
// TODO: remove this and all usage of `executions.process` when we're sure that nobody has this in their config file anymore.
process: {

View file

@ -99,7 +99,7 @@ export class FrontendService {
saveExecutionProgress: config.getEnv('executions.saveExecutionProgress'),
executionTimeout: config.getEnv('executions.timeout'),
maxExecutionTimeout: config.getEnv('executions.maxTimeout'),
workflowCallerPolicyDefaultOption: config.getEnv('workflows.callerPolicyDefaultOption'),
workflowCallerPolicyDefaultOption: this.globalConfig.workflows.callerPolicyDefaultOption,
timezone: config.getEnv('generic.timezone'),
urlBaseWebhook: this.urlService.getWebhookBaseUrl(),
urlBaseEditor: instanceBaseUrl,

View file

@ -10,6 +10,7 @@ import { SubworkflowPolicyChecker } from '../subworkflow-policy-checker.service'
import type { WorkflowEntity } from '@/databases/entities/WorkflowEntity';
import type { License } from '@/License';
import type { GlobalConfig } from '@n8n/config';
const toTargetCallErrorMsg = (subworkflowId: string) =>
`Target workflow ID ${subworkflowId} may not be called`;
@ -19,7 +20,10 @@ const memberPersonalProject = mock<Project>();
describe('SubworkflowPolicyChecker', () => {
const license = mock<License>();
const checker = new SubworkflowPolicyChecker(mock(), license, ownershipService);
const globalConfig = mock<GlobalConfig>({
workflows: { callerPolicyDefaultOption: 'workflowsFromSameOwner' },
});
const checker = new SubworkflowPolicyChecker(mock(), license, ownershipService, globalConfig);
beforeEach(() => {
license.isSharingEnabled.mockReturnValue(true);
@ -31,7 +35,12 @@ describe('SubworkflowPolicyChecker', () => {
describe('no caller policy', () => {
test('should fall back to N8N_WORKFLOW_CALLER_POLICY_DEFAULT_OPTION', async () => {
config.set('workflows.callerPolicyDefaultOption', 'none');
const checker = new SubworkflowPolicyChecker(
mock(),
license,
ownershipService,
mock<GlobalConfig>({ workflows: { callerPolicyDefaultOption: 'none' } }),
);
const parentWorkflow = mock<WorkflowEntity>();
const subworkflow = mock<Workflow>(); // no caller policy

View file

@ -1,6 +1,6 @@
import { Service } from 'typedi';
import { WorkflowOperationError } from 'n8n-workflow';
import config from '@/config';
import { GlobalConfig } from '@n8n/config';
import { Logger } from '@/Logger';
import { License } from '@/License';
import { OwnershipService } from '@/services/ownership.service';
@ -12,6 +12,7 @@ export class SubworkflowPolicyChecker {
private readonly logger: Logger,
private readonly license: License,
private readonly ownershipService: OwnershipService,
private readonly globalConfig: GlobalConfig,
) {}
async check(subworkflow: Workflow, parentWorkflowId: string, node?: INode) {
@ -28,7 +29,7 @@ export class SubworkflowPolicyChecker {
}
let policy =
subworkflow.settings?.callerPolicy ?? config.getEnv('workflows.callerPolicyDefaultOption');
subworkflow.settings?.callerPolicy ?? this.globalConfig.workflows.callerPolicyDefaultOption;
const isSharingEnabled = this.license.isSharingEnabled();

View file

@ -43,6 +43,7 @@ import type { Project } from '@/databases/entities/Project';
import { ProjectRelationRepository } from '@/databases/repositories/projectRelation.repository';
import { z } from 'zod';
import { EventService } from '@/eventbus/event.service';
import { GlobalConfig } from '@n8n/config';
@RestController('/workflows')
export class WorkflowsController {
@ -67,6 +68,7 @@ export class WorkflowsController {
private readonly projectService: ProjectService,
private readonly projectRelationRepository: ProjectRelationRepository,
private readonly eventService: EventService,
private readonly globalConfig: GlobalConfig,
) {}
@Post('/')
@ -204,12 +206,12 @@ export class WorkflowsController {
@Get('/new')
async getNewName(req: WorkflowRequest.NewName) {
const requestedName = req.query.name ?? config.getEnv('workflows.defaultName');
const requestedName = req.query.name ?? this.globalConfig.workflows.defaultName;
const name = await this.namingService.getUniqueWorkflowName(requestedName);
const onboardingFlowEnabled =
!config.getEnv('workflows.onboardingFlowDisabled') &&
!this.globalConfig.workflows.onboardingFlowDisabled &&
!req.user.settings?.isOnboarded &&
(await this.userOnboardingService.isBelowThreshold(req.user));