refactor: Use string ids on Credentials, Workflows, Tags, and Executions DB entities (#5041)
This commit is contained in:
committed by
GitHub
parent
8bee04cd2a
commit
ee28213538
@@ -92,7 +92,7 @@ EEWorkflowController.get(
|
||||
relations.push('tags');
|
||||
}
|
||||
|
||||
const workflow = await EEWorkflows.get({ id: parseInt(workflowId, 10) }, { relations });
|
||||
const workflow = await EEWorkflows.get({ id: workflowId }, { relations });
|
||||
|
||||
if (!workflow) {
|
||||
throw new ResponseHelper.NotFoundError(`Workflow with ID "${workflowId}" does not exist`);
|
||||
@@ -108,7 +108,7 @@ EEWorkflowController.get(
|
||||
|
||||
EEWorkflows.addOwnerAndSharings(workflow);
|
||||
await EEWorkflows.addCredentialsToWorkflow(workflow, req.user);
|
||||
return EEWorkflows.entityToResponse(workflow);
|
||||
return workflow;
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -189,7 +189,7 @@ EEWorkflowController.post(
|
||||
await ExternalHooks().run('workflow.afterCreate', [savedWorkflow]);
|
||||
void InternalHooksManager.getInstance().onWorkflowCreated(req.user.id, newWorkflow, false);
|
||||
|
||||
return EEWorkflows.entityToResponse(savedWorkflow);
|
||||
return savedWorkflow;
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -205,7 +205,7 @@ EEWorkflowController.get(
|
||||
return workflows.map((workflow) => {
|
||||
EEWorkflows.addOwnerAndSharings(workflow);
|
||||
workflow.nodes = [];
|
||||
return EEWorkflows.entityToResponse(workflow);
|
||||
return workflow;
|
||||
});
|
||||
}),
|
||||
);
|
||||
@@ -230,7 +230,7 @@ EEWorkflowController.patch(
|
||||
forceSave,
|
||||
);
|
||||
|
||||
return EEWorkflows.entityToResponse(updatedWorkflow);
|
||||
return updatedWorkflow;
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -244,11 +244,7 @@ EEWorkflowController.post(
|
||||
Object.assign(workflow, req.body.workflowData);
|
||||
|
||||
if (workflow.id !== undefined) {
|
||||
const safeWorkflow = await EEWorkflows.preventTampering(
|
||||
workflow,
|
||||
workflow.id.toString(),
|
||||
req.user,
|
||||
);
|
||||
const safeWorkflow = await EEWorkflows.preventTampering(workflow, workflow.id, req.user);
|
||||
req.body.workflowData.nodes = safeWorkflow.nodes;
|
||||
}
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ workflowsController.post(
|
||||
await ExternalHooks().run('workflow.afterCreate', [savedWorkflow]);
|
||||
void InternalHooksManager.getInstance().onWorkflowCreated(req.user.id, newWorkflow, false);
|
||||
|
||||
return WorkflowsService.entityToResponse(savedWorkflow);
|
||||
return savedWorkflow;
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -116,8 +116,7 @@ workflowsController.post(
|
||||
workflowsController.get(
|
||||
'/',
|
||||
ResponseHelper.send(async (req: WorkflowRequest.GetAll) => {
|
||||
const workflows = await WorkflowsService.getMany(req.user, req.query.filter);
|
||||
return workflows.map((workflow) => WorkflowsService.entityToResponse(workflow));
|
||||
return WorkflowsService.getMany(req.user, req.query.filter);
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -218,7 +217,7 @@ workflowsController.get(
|
||||
);
|
||||
}
|
||||
|
||||
return WorkflowsService.entityToResponse(shared.workflow);
|
||||
return shared.workflow;
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -244,7 +243,7 @@ workflowsController.patch(
|
||||
['owner'],
|
||||
);
|
||||
|
||||
return WorkflowsService.entityToResponse(updatedWorkflow);
|
||||
return updatedWorkflow;
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
@@ -42,7 +42,8 @@ export class EEWorkflowsService extends WorkflowsService {
|
||||
transaction: EntityManager,
|
||||
workflowId: string,
|
||||
): Promise<SharedWorkflow[]> {
|
||||
const workflow = await transaction.findOne(WorkflowEntity, workflowId, {
|
||||
const workflow = await transaction.findOne(WorkflowEntity, {
|
||||
where: { id: workflowId },
|
||||
relations: ['shared'],
|
||||
});
|
||||
return workflow?.shared ?? [];
|
||||
@@ -54,8 +55,8 @@ export class EEWorkflowsService extends WorkflowsService {
|
||||
userIds: string[],
|
||||
): Promise<DeleteResult> {
|
||||
return transaction.delete(SharedWorkflow, {
|
||||
workflow: { id: workflowId },
|
||||
user: { id: Not(In(userIds)) },
|
||||
workflowId,
|
||||
userId: Not(In(userIds)),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -113,7 +114,7 @@ export class EEWorkflowsService extends WorkflowsService {
|
||||
): Promise<void> {
|
||||
workflow.usedCredentials = [];
|
||||
const userCredentials = await EECredentials.getAll(currentUser, { disableGlobalRole: true });
|
||||
const credentialIdsUsedByWorkflow = new Set<number>();
|
||||
const credentialIdsUsedByWorkflow = new Set<string>();
|
||||
workflow.nodes.forEach((node) => {
|
||||
if (!node.credentials) {
|
||||
return;
|
||||
@@ -123,8 +124,7 @@ export class EEWorkflowsService extends WorkflowsService {
|
||||
if (!credential?.id) {
|
||||
return;
|
||||
}
|
||||
const credentialId = parseInt(credential.id, 10);
|
||||
credentialIdsUsedByWorkflow.add(credentialId);
|
||||
credentialIdsUsedByWorkflow.add(credential.id);
|
||||
});
|
||||
});
|
||||
const workflowCredentials = await EECredentials.getMany({
|
||||
@@ -133,11 +133,11 @@ export class EEWorkflowsService extends WorkflowsService {
|
||||
},
|
||||
relations: ['shared', 'shared.user', 'shared.role'],
|
||||
});
|
||||
const userCredentialIds = userCredentials.map((credential) => credential.id.toString());
|
||||
const userCredentialIds = userCredentials.map((credential) => credential.id);
|
||||
workflowCredentials.forEach((credential) => {
|
||||
const credentialId = credential.id.toString();
|
||||
const credentialId = credential.id;
|
||||
const workflowCredential: CredentialUsedByWorkflow = {
|
||||
id: credential.id.toString(),
|
||||
id: credentialId,
|
||||
name: credential.name,
|
||||
type: credential.type,
|
||||
currentUserHasAccess: userCredentialIds.includes(credentialId),
|
||||
@@ -190,23 +190,24 @@ export class EEWorkflowsService extends WorkflowsService {
|
||||
relations: ['shared', 'shared.user', 'shared.role'],
|
||||
});
|
||||
const userCredentials = await EECredentials.getAll(currentUser, { disableGlobalRole: true });
|
||||
const userCredentialIds = userCredentials.map((credential) => credential.id.toString());
|
||||
const userCredentialIds = userCredentials.map((credential) => credential.id);
|
||||
const credentialsMap: Record<string, CredentialUsedByWorkflow> = {};
|
||||
usedWorkflowsCredentials.forEach((credential) => {
|
||||
credentialsMap[credential.id.toString()] = {
|
||||
id: credential.id.toString(),
|
||||
const credentialId = credential.id;
|
||||
credentialsMap[credentialId] = {
|
||||
id: credentialId,
|
||||
name: credential.name,
|
||||
type: credential.type,
|
||||
currentUserHasAccess: userCredentialIds.includes(credential.id.toString()),
|
||||
currentUserHasAccess: userCredentialIds.includes(credentialId),
|
||||
sharedWith: [],
|
||||
ownedBy: null,
|
||||
};
|
||||
credential.shared?.forEach(({ user, role }) => {
|
||||
const { id, email, firstName, lastName } = user;
|
||||
if (role.name === 'owner') {
|
||||
credentialsMap[credential.id.toString()].ownedBy = { id, email, firstName, lastName };
|
||||
credentialsMap[credentialId].ownedBy = { id, email, firstName, lastName };
|
||||
} else {
|
||||
credentialsMap[credential.id.toString()].sharedWith?.push({
|
||||
credentialsMap[credentialId].sharedWith?.push({
|
||||
id,
|
||||
email,
|
||||
firstName,
|
||||
@@ -230,10 +231,9 @@ export class EEWorkflowsService extends WorkflowsService {
|
||||
return;
|
||||
}
|
||||
Object.keys(node.credentials).forEach((credentialType) => {
|
||||
const credentialId = parseInt(node.credentials?.[credentialType].id ?? '', 10);
|
||||
const matchedCredential = allowedCredentials.find(
|
||||
(credential) => credential.id === credentialId,
|
||||
);
|
||||
const credentialId = node.credentials?.[credentialType].id;
|
||||
if (credentialId === undefined) return;
|
||||
const matchedCredential = allowedCredentials.find(({ id }) => id === credentialId);
|
||||
if (!matchedCredential) {
|
||||
throw new Error('The workflow contains credentials that you do not have access to');
|
||||
}
|
||||
@@ -242,7 +242,7 @@ export class EEWorkflowsService extends WorkflowsService {
|
||||
}
|
||||
|
||||
static async preventTampering(workflow: WorkflowEntity, workflowId: string, user: User) {
|
||||
const previousVersion = await EEWorkflowsService.get({ id: parseInt(workflowId, 10) });
|
||||
const previousVersion = await EEWorkflowsService.get({ id: workflowId });
|
||||
|
||||
if (!previousVersion) {
|
||||
throw new ResponseHelper.NotFoundError('Workflow not found');
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { validate as jsonSchemaValidate } from 'jsonschema';
|
||||
import { INode, IPinData, JsonObject, jsonParse, LoggerProxy, Workflow } from 'n8n-workflow';
|
||||
import { FindManyOptions, FindOneOptions, In, ObjectLiteral } from 'typeorm';
|
||||
import { FindConditions, In } from 'typeorm';
|
||||
import pick from 'lodash.pick';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import * as ActiveWorkflowRunner from '@/ActiveWorkflowRunner';
|
||||
@@ -16,7 +16,7 @@ import { validateEntity } from '@/GenericHelpers';
|
||||
import { ExternalHooks } from '@/ExternalHooks';
|
||||
import * as TagHelpers from '@/TagHelpers';
|
||||
import { WorkflowRequest } from '@/requests';
|
||||
import { IWorkflowDb, IWorkflowExecutionDataProcess, IWorkflowResponse } from '@/Interfaces';
|
||||
import type { IWorkflowDb, IWorkflowExecutionDataProcess } from '@/Interfaces';
|
||||
import { NodeTypes } from '@/NodeTypes';
|
||||
import { WorkflowRunner } from '@/WorkflowRunner';
|
||||
import * as WorkflowExecuteAdditionalData from '@/WorkflowExecuteAdditionalData';
|
||||
@@ -25,7 +25,7 @@ import { getSharedWorkflowIds } from '@/WorkflowHelpers';
|
||||
import { isSharingEnabled, whereClause } from '@/UserManagement/UserManagementHelper';
|
||||
|
||||
export interface IGetWorkflowsQueryFilter {
|
||||
id?: number | string;
|
||||
id?: string;
|
||||
name?: string;
|
||||
active?: boolean;
|
||||
}
|
||||
@@ -45,28 +45,20 @@ const allowedWorkflowsQueryFilterFields = Object.keys(schemaGetWorkflowsQueryFil
|
||||
export class WorkflowsService {
|
||||
static async getSharing(
|
||||
user: User,
|
||||
workflowId: number | string,
|
||||
workflowId: string,
|
||||
relations: string[] = ['workflow'],
|
||||
{ allowGlobalOwner } = { allowGlobalOwner: true },
|
||||
): Promise<SharedWorkflow | undefined> {
|
||||
const options: FindOneOptions<SharedWorkflow> & { where: ObjectLiteral } = {
|
||||
where: {
|
||||
workflow: { id: workflowId },
|
||||
},
|
||||
};
|
||||
const where: FindConditions<SharedWorkflow> = { workflowId };
|
||||
|
||||
// Omit user from where if the requesting user is the global
|
||||
// owner. This allows the global owner to view and delete
|
||||
// workflows they don't own.
|
||||
if (!allowGlobalOwner || user.globalRole.name !== 'owner') {
|
||||
options.where.user = { id: user.id };
|
||||
where.userId = user.id;
|
||||
}
|
||||
|
||||
if (relations?.length) {
|
||||
options.relations = relations;
|
||||
}
|
||||
|
||||
return Db.collections.SharedWorkflow.findOne(options);
|
||||
return Db.collections.SharedWorkflow.findOne({ where, relations });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,11 +112,6 @@ export class WorkflowsService {
|
||||
return getSharedWorkflowIds(user, roles);
|
||||
}
|
||||
|
||||
static entityToResponse(entity: WorkflowEntity): IWorkflowResponse {
|
||||
const { id, ...rest } = entity;
|
||||
return { ...rest, id: id.toString() };
|
||||
}
|
||||
|
||||
static async getMany(user: User, rawFilter: string): Promise<WorkflowEntity[]> {
|
||||
const sharedWorkflowIds = await this.getWorkflowIdsForUser(user, ['owner']);
|
||||
if (sharedWorkflowIds.length === 0) {
|
||||
@@ -181,16 +168,14 @@ export class WorkflowsService {
|
||||
relations.push('shared', 'shared.user', 'shared.role');
|
||||
}
|
||||
|
||||
const query: FindManyOptions<WorkflowEntity> = {
|
||||
return Db.collections.Workflow.find({
|
||||
select: isSharingEnabled() ? [...fields, 'versionId'] : fields,
|
||||
relations,
|
||||
where: {
|
||||
id: In(sharedWorkflowIds),
|
||||
...filter,
|
||||
},
|
||||
};
|
||||
|
||||
return Db.collections.Workflow.find(query);
|
||||
});
|
||||
}
|
||||
|
||||
static async update(
|
||||
@@ -310,17 +295,11 @@ export class WorkflowsService {
|
||||
}
|
||||
}
|
||||
|
||||
const options: FindManyOptions<WorkflowEntity> = {
|
||||
relations: ['tags'],
|
||||
};
|
||||
|
||||
if (config.getEnv('workflowTagsDisabled')) {
|
||||
delete options.relations;
|
||||
}
|
||||
const relations = config.getEnv('workflowTagsDisabled') ? [] : ['tags'];
|
||||
|
||||
// We sadly get nothing back from "update". Neither if it updated a record
|
||||
// nor the new value. So query now the hopefully updated entry.
|
||||
const updatedWorkflow = await Db.collections.Workflow.findOne(workflowId, options);
|
||||
const updatedWorkflow = await Db.collections.Workflow.findOne(workflowId, { relations });
|
||||
|
||||
if (updatedWorkflow === undefined) {
|
||||
throw new ResponseHelper.BadRequestError(
|
||||
|
||||
Reference in New Issue
Block a user