refactor: Workflow sharing bug bash fixes (#4888)

* fix: Prevent workflows with only manual trigger from being activated

* fix: Fix workflow id when sharing from workflows list

* fix: Update sharing modal translations

* fix: Allow sharees to disable workflows and fix issue with unique key when removing a user

* refactor: Improve error messages and change logging level to be less verbose

* fix: Broken user removal transfer issue

* feat: Implement workflow sharing BE telemetry

* chore: temporarily add sharing env vars

* feat: Implement BE telemetry for workflow sharing

* fix: Prevent issues with possibly missing workflow id

* feat: Replace WorkflowSharing flag references (no-changelog) (#4918)

* ci: Block all external network calls in tests (no-changelog) (#4930)

* setup nock to prevent tests from making any external requests

* mock all calls to posthog sdk

* feat: Replace WorkflowSharing flag references (no-changelog)

Co-authored-by: कारतोफ्फेलस्क्रिप्ट™ <netroy@users.noreply.github.com>

* refactor: Remove temporary feature flag for workflow sharing

* refactor: add sharing_role to both manual and node executions

* refactor: Allow changing name, position and disabled of read only nodes

* feat: Overhaul dynamic translations for local and cloud (#4943)

* feat: Overhaul dynamic translations for local and cloud

* fix: remove type casting

* chore: remove unused translations

* fix: fix workflow sharing translation

* test: Fix broken test

* refactor: remove unnecessary import

* refactor: Minor code improvements

* refactor: rename dynamicTranslations to contextBasedTranslationKeys

* fix: fix type imports

* refactor: Consolidate sharing feature check

* feat: update cred sharing unavailable translations

* feat: update upgrade message when user management not available

* fix: rename plan names to Pro and Power

* feat: update translations to no longer contain plan names

* wip: subworkflow permissions

* feat: add workflowsFromSameOwner caller policy

* feat: Fix subworkflow permissions

* shared entites should check for role when deleting users

* refactor: remove circular dependency

* role filter shouldn't be an array

* fixed role issue

* fix: Corrected behavior when removing users

* feat: show instance owner credential sharing message only if isnt sharee

* feat: update workflow caller policy caller ids labels

* feat: update upgrade plan links to contain instance ids

* fix: show check errors below creds message only to owner

* fix(editor): Hide usage page on cloud

* fix: update credential validation error message for sharee

* fix(core): Remove duplicate import

* fix(editor): Extending deployment types

* feat: Overhaul contextual translations (#4992)

feat: update how contextual translations work

* refactor: improve messageing for subworkflow permissions

* test: Fix issue with user deletion and transfer

* fix: Explicitly throw error message so it can be displayed in UI

Co-authored-by: Alex Grozav <alex@grozav.com>
Co-authored-by: कारतोफ्फेलस्क्रिप्ट™ <netroy@users.noreply.github.com>
Co-authored-by: freyamade <freya@n8n.io>
Co-authored-by: Csaba Tuncsik <csaba@n8n.io>
This commit is contained in:
Omar Ajoue
2022-12-21 16:42:07 +01:00
committed by GitHub
parent e225c3190e
commit 25e9f0817a
43 changed files with 597 additions and 344 deletions

View File

@@ -65,6 +65,7 @@ import * as WorkflowHelpers from '@/WorkflowHelpers';
import { getUserById, getWorkflowOwner, whereClause } from '@/UserManagement/UserManagementHelper';
import { findSubworkflowStart } from '@/utils';
import { PermissionChecker } from './UserManagement/PermissionChecker';
import { WorkflowsService } from './workflows/workflows.services';
const ERROR_TRIGGER_TYPE = config.getEnv('nodes.errorTriggerType');
@@ -779,34 +780,6 @@ export async function getRunData(
): Promise<IWorkflowExecutionDataProcess> {
const mode = 'integrated';
const policy =
workflowData.settings?.callerPolicy ?? config.getEnv('workflows.callerPolicyDefaultOption');
if (policy === 'none') {
throw new SubworkflowOperationError(
`Target workflow ID ${workflowData.id} may not be called by other workflows.`,
'Please update the settings of the target workflow or ask its owner to do so.',
);
}
if (
policy === 'workflowsFromAList' &&
typeof workflowData.settings?.callerIds === 'string' &&
parentWorkflowId !== undefined
) {
const allowedCallerIds = workflowData.settings.callerIds
.split(',')
.map((id) => id.trim())
.filter((id) => id !== '');
if (!allowedCallerIds.includes(parentWorkflowId)) {
throw new SubworkflowOperationError(
`Target workflow ID ${workflowData.id} may only be called by a list of workflows, which does not include current workflow ID ${parentWorkflowId}.`,
'Please update the settings of the target workflow or ask its owner to do so.',
);
}
}
const startingNode = findSubworkflowStart(workflowData.nodes);
// Always start with empty data if no inputData got supplied
@@ -852,7 +825,6 @@ export async function getRunData(
export async function getWorkflowData(
workflowInfo: IExecuteWorkflowInfo,
userId: string,
parentWorkflowId?: string,
parentWorkflowSettings?: IWorkflowSettings,
): Promise<IWorkflowBase> {
@@ -869,23 +841,15 @@ export async function getWorkflowData(
// to get initialized first
await Db.init();
}
const user = await getUserById(userId);
let relations = ['workflow', 'workflow.tags'];
if (config.getEnv('workflowTagsDisabled')) {
relations = relations.filter((relation) => relation !== 'workflow.tags');
}
const relations = config.getEnv('workflowTagsDisabled') ? [] : ['tags'];
const shared = await Db.collections.SharedWorkflow.findOne({
relations,
where: whereClause({
user,
entityType: 'workflow',
entityId: workflowInfo.id,
}),
});
workflowData = shared?.workflow;
workflowData = await WorkflowsService.get(
{ id: parseInt(workflowInfo.id, 10) },
{
relations,
},
);
if (workflowData === undefined) {
throw new Error(`The workflow with the id "${workflowInfo.id}" does not exist.`);
@@ -911,7 +875,7 @@ export async function getWorkflowData(
async function executeWorkflow(
workflowInfo: IExecuteWorkflowInfo,
additionalData: IWorkflowExecuteAdditionalData,
options?: {
options: {
parentWorkflowId?: string;
inputData?: INodeExecutionData[];
parentExecutionId?: string;
@@ -926,13 +890,8 @@ async function executeWorkflow(
const nodeTypes = NodeTypes();
const workflowData =
options?.loadedWorkflowData ??
(await getWorkflowData(
workflowInfo,
additionalData.userId,
options?.parentWorkflowId,
options?.parentWorkflowSettings,
));
options.loadedWorkflowData ??
(await getWorkflowData(workflowInfo, options.parentWorkflowId, options.parentWorkflowSettings));
const workflowName = workflowData ? workflowData.name : undefined;
const workflow = new Workflow({
@@ -947,23 +906,28 @@ async function executeWorkflow(
});
const runData =
options?.loadedRunData ??
(await getRunData(workflowData, additionalData.userId, options?.inputData));
options.loadedRunData ??
(await getRunData(workflowData, additionalData.userId, options.inputData));
let executionId;
if (options?.parentExecutionId !== undefined) {
executionId = options?.parentExecutionId;
if (options.parentExecutionId !== undefined) {
executionId = options.parentExecutionId;
} else {
executionId =
options?.parentExecutionId !== undefined
? options?.parentExecutionId
options.parentExecutionId !== undefined
? options.parentExecutionId
: await ActiveExecutions.getInstance().add(runData);
}
let data;
try {
await PermissionChecker.check(workflow, additionalData.userId);
await PermissionChecker.checkSubworkflowExecutePolicy(
workflow,
additionalData.userId,
options.parentWorkflowId,
);
// Create new additionalData to have different workflow loaded and to call
// different webhooks
@@ -1005,7 +969,7 @@ async function executeWorkflow(
runData.executionMode,
runExecutionData,
);
if (options?.parentExecutionId !== undefined) {
if (options.parentExecutionId !== undefined) {
// Must be changed to become typed
return {
startedAt: new Date(),
@@ -1049,6 +1013,7 @@ async function executeWorkflow(
throw {
...error,
stack: error.stack,
message: error.message,
};
}