mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-10 06:34:05 -08:00
refactor(core): Convert workflows controller to DI (no-changelog) (#8253)
This commit is contained in:
parent
ac1c642fdd
commit
90c065e999
|
@ -30,7 +30,7 @@ import config from '@/config';
|
|||
import { Queue } from '@/Queue';
|
||||
import { getSharedWorkflowIds } from '@/WorkflowHelpers';
|
||||
|
||||
import { workflowsController } from '@/workflows/workflows.controller';
|
||||
import { WorkflowsController } from '@/workflows/workflows.controller';
|
||||
import {
|
||||
EDITOR_UI_DIST_DIR,
|
||||
inDevelopment,
|
||||
|
@ -246,10 +246,11 @@ export class Server extends AbstractServer {
|
|||
VariablesController,
|
||||
RoleController,
|
||||
ActiveWorkflowsController,
|
||||
WorkflowsController,
|
||||
];
|
||||
|
||||
if (process.env.NODE_ENV !== 'production' && Container.get(MultiMainSetup).isEnabled) {
|
||||
const { DebugController } = await import('./controllers/debug.controller');
|
||||
const { DebugController } = await import('@/controllers/debug.controller');
|
||||
controllers.push(DebugController);
|
||||
}
|
||||
|
||||
|
@ -358,11 +359,6 @@ export class Server extends AbstractServer {
|
|||
|
||||
this.app.use(`/${this.restEndpoint}/credentials`, credentialsController);
|
||||
|
||||
// ----------------------------------------
|
||||
// Workflow
|
||||
// ----------------------------------------
|
||||
this.app.use(`/${this.restEndpoint}/workflows`, workflowsController);
|
||||
|
||||
// ----------------------------------------
|
||||
// SAML
|
||||
// ----------------------------------------
|
||||
|
|
|
@ -4,23 +4,3 @@ import { License } from '@/License';
|
|||
export function isSharingEnabled(): boolean {
|
||||
return Container.get(License).isSharingEnabled();
|
||||
}
|
||||
|
||||
// return the difference between two arrays
|
||||
export function rightDiff<T1, T2>(
|
||||
[arr1, keyExtractor1]: [T1[], (item: T1) => string],
|
||||
[arr2, keyExtractor2]: [T2[], (item: T2) => string],
|
||||
): T2[] {
|
||||
// create map { itemKey => true } for fast lookup for diff
|
||||
const keyMap = arr1.reduce<{ [key: string]: true }>((map, item) => {
|
||||
map[keyExtractor1(item)] = true;
|
||||
return map;
|
||||
}, {});
|
||||
|
||||
// diff against map
|
||||
return arr2.reduce<T2[]>((acc, item) => {
|
||||
if (!keyMap[keyExtractor2(item)]) {
|
||||
acc.push(item);
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Authorized, Get, RestController } from '@/decorators';
|
||||
import { WorkflowRequest } from '@/requests';
|
||||
import { ActiveWorkflowRequest } from '@/requests';
|
||||
import { ActiveWorkflowsService } from '@/services/activeWorkflows.service';
|
||||
|
||||
@Authorized()
|
||||
|
@ -8,12 +8,12 @@ export class ActiveWorkflowsController {
|
|||
constructor(private readonly activeWorkflowsService: ActiveWorkflowsService) {}
|
||||
|
||||
@Get('/')
|
||||
async getActiveWorkflows(req: WorkflowRequest.GetAllActive) {
|
||||
async getActiveWorkflows(req: ActiveWorkflowRequest.GetAllActive) {
|
||||
return this.activeWorkflowsService.getAllActiveIdsFor(req.user);
|
||||
}
|
||||
|
||||
@Get('/error/:id')
|
||||
async getActivationError(req: WorkflowRequest.GetActivationError) {
|
||||
async getActivationError(req: ActiveWorkflowRequest.GetActivationError) {
|
||||
const {
|
||||
user,
|
||||
params: { id: workflowId },
|
||||
|
|
|
@ -5,7 +5,7 @@ import * as Db from '@/Db';
|
|||
import * as ResponseHelper from '@/ResponseHelper';
|
||||
|
||||
import type { CredentialRequest } from '@/requests';
|
||||
import { isSharingEnabled, rightDiff } from '@/UserManagement/UserManagementHelper';
|
||||
import { isSharingEnabled } from '@/UserManagement/UserManagementHelper';
|
||||
import { EECredentialsService as EECredentials } from './credentials.service.ee';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { Container } from 'typedi';
|
||||
|
@ -14,6 +14,7 @@ import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
|||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
import { UnauthorizedError } from '@/errors/response-errors/unauthorized.error';
|
||||
import { CredentialsRepository } from '@/databases/repositories/credentials.repository';
|
||||
import * as utils from '@/utils';
|
||||
|
||||
export const EECredentialsController = express.Router();
|
||||
|
||||
|
@ -165,7 +166,7 @@ EECredentialsController.put(
|
|||
const sharings = await EECredentials.getSharings(trx, credentialId);
|
||||
|
||||
// extract the new sharings that need to be added
|
||||
newShareeIds = rightDiff(
|
||||
newShareeIds = utils.rightDiff(
|
||||
[sharings, (sharing) => sharing.userId],
|
||||
[shareWithIds, (shareeId) => shareeId],
|
||||
);
|
||||
|
|
|
@ -1,19 +1,14 @@
|
|||
import type express from 'express';
|
||||
import type {
|
||||
BannerName,
|
||||
IConnections,
|
||||
ICredentialDataDecryptedObject,
|
||||
ICredentialNodeAccess,
|
||||
IDataObject,
|
||||
INode,
|
||||
INodeCredentialTestRequest,
|
||||
INodeCredentials,
|
||||
INodeParameters,
|
||||
INodeTypeNameVersion,
|
||||
IPinData,
|
||||
IRunData,
|
||||
IUser,
|
||||
IWorkflowSettings,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { IsBoolean, IsEmail, IsIn, IsOptional, IsString, Length } from 'class-validator';
|
||||
|
@ -21,7 +16,6 @@ import { NoXss } from '@db/utils/customValidators';
|
|||
import type {
|
||||
PublicUser,
|
||||
IExecutionDeleteFilter,
|
||||
IWorkflowDb,
|
||||
SecretsProvider,
|
||||
SecretsProviderState,
|
||||
} from '@/Interfaces';
|
||||
|
@ -81,55 +75,6 @@ export type AuthenticatedRequest<
|
|||
globalMemberRole?: Role;
|
||||
};
|
||||
|
||||
// ----------------------------------
|
||||
// /workflows
|
||||
// ----------------------------------
|
||||
|
||||
export declare namespace WorkflowRequest {
|
||||
type CreateUpdatePayload = Partial<{
|
||||
id: string; // delete if sent
|
||||
name: string;
|
||||
nodes: INode[];
|
||||
connections: IConnections;
|
||||
settings: IWorkflowSettings;
|
||||
active: boolean;
|
||||
tags: string[];
|
||||
hash: string;
|
||||
meta: Record<string, unknown>;
|
||||
}>;
|
||||
|
||||
type ManualRunPayload = {
|
||||
workflowData: IWorkflowDb;
|
||||
runData: IRunData;
|
||||
pinData: IPinData;
|
||||
startNodes?: string[];
|
||||
destinationNode?: string;
|
||||
};
|
||||
|
||||
type Create = AuthenticatedRequest<{}, {}, CreateUpdatePayload>;
|
||||
|
||||
type Get = AuthenticatedRequest<{ id: string }>;
|
||||
|
||||
type Delete = Get;
|
||||
|
||||
type Update = AuthenticatedRequest<
|
||||
{ id: string },
|
||||
{},
|
||||
CreateUpdatePayload,
|
||||
{ forceSave?: string }
|
||||
>;
|
||||
|
||||
type NewName = AuthenticatedRequest<{}, {}, {}, { name?: string }>;
|
||||
|
||||
type GetAllActive = AuthenticatedRequest;
|
||||
|
||||
type GetActivationError = Get;
|
||||
|
||||
type ManualRun = AuthenticatedRequest<{}, {}, ManualRunPayload>;
|
||||
|
||||
type Share = AuthenticatedRequest<{ workflowId: string }, {}, { shareWithIds: string[] }>;
|
||||
}
|
||||
|
||||
// ----------------------------------
|
||||
// list query
|
||||
// ----------------------------------
|
||||
|
@ -219,7 +164,7 @@ export declare namespace CredentialRequest {
|
|||
|
||||
type Update = AuthenticatedRequest<{ id: string }, {}, CredentialProperties>;
|
||||
|
||||
type NewName = WorkflowRequest.NewName;
|
||||
type NewName = AuthenticatedRequest<{}, {}, {}, { name?: string }>;
|
||||
|
||||
type Test = AuthenticatedRequest<{}, {}, INodeCredentialTestRequest>;
|
||||
|
||||
|
@ -576,3 +521,13 @@ export declare namespace WorkflowHistoryRequest {
|
|||
WorkflowHistory
|
||||
>;
|
||||
}
|
||||
|
||||
// ----------------------------------
|
||||
// /active-workflows
|
||||
// ----------------------------------
|
||||
|
||||
export declare namespace ActiveWorkflowRequest {
|
||||
type GetAllActive = AuthenticatedRequest;
|
||||
|
||||
type GetActivationError = AuthenticatedRequest<{ id: string }>;
|
||||
}
|
||||
|
|
|
@ -77,3 +77,23 @@ export function isObjectLiteral(item: unknown): item is { [key: string]: string
|
|||
export function removeTrailingSlash(path: string) {
|
||||
return path.endsWith('/') ? path.slice(0, -1) : path;
|
||||
}
|
||||
|
||||
// return the difference between two arrays
|
||||
export function rightDiff<T1, T2>(
|
||||
[arr1, keyExtractor1]: [T1[], (item: T1) => string],
|
||||
[arr2, keyExtractor2]: [T2[], (item: T2) => string],
|
||||
): T2[] {
|
||||
// create map { itemKey => true } for fast lookup for diff
|
||||
const keyMap = arr1.reduce<{ [key: string]: true }>((map, item) => {
|
||||
map[keyExtractor1(item)] = true;
|
||||
return map;
|
||||
}, {});
|
||||
|
||||
// diff against map
|
||||
return arr2.reduce<T2[]>((acc, item) => {
|
||||
if (!keyMap[keyExtractor2(item)]) {
|
||||
acc.push(item);
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
}
|
||||
|
|
46
packages/cli/src/workflows/workflow.request.ts
Normal file
46
packages/cli/src/workflows/workflow.request.ts
Normal file
|
@ -0,0 +1,46 @@
|
|||
import type { IWorkflowDb } from '@/Interfaces';
|
||||
import type { AuthenticatedRequest } from '@/requests';
|
||||
import type { INode, IConnections, IWorkflowSettings, IRunData, IPinData } from 'n8n-workflow';
|
||||
|
||||
export declare namespace WorkflowRequest {
|
||||
type CreateUpdatePayload = Partial<{
|
||||
id: string; // delete if sent
|
||||
name: string;
|
||||
nodes: INode[];
|
||||
connections: IConnections;
|
||||
settings: IWorkflowSettings;
|
||||
active: boolean;
|
||||
tags: string[];
|
||||
hash: string;
|
||||
meta: Record<string, unknown>;
|
||||
}>;
|
||||
|
||||
type ManualRunPayload = {
|
||||
workflowData: IWorkflowDb;
|
||||
runData: IRunData;
|
||||
pinData: IPinData;
|
||||
startNodes?: string[];
|
||||
destinationNode?: string;
|
||||
};
|
||||
|
||||
type Create = AuthenticatedRequest<{}, {}, CreateUpdatePayload>;
|
||||
|
||||
type Get = AuthenticatedRequest<{ id: string }>;
|
||||
|
||||
type Delete = Get;
|
||||
|
||||
type Update = AuthenticatedRequest<
|
||||
{ id: string },
|
||||
{},
|
||||
CreateUpdatePayload,
|
||||
{ forceSave?: string }
|
||||
>;
|
||||
|
||||
type NewName = AuthenticatedRequest<{}, {}, {}, { name?: string }>;
|
||||
|
||||
type ManualRun = AuthenticatedRequest<{}, {}, ManualRunPayload>;
|
||||
|
||||
type Share = AuthenticatedRequest<{ workflowId: string }, {}, { shareWithIds: string[] }>;
|
||||
|
||||
type FromUrl = AuthenticatedRequest<{}, {}, {}, { url?: string }>;
|
||||
}
|
|
@ -11,7 +11,8 @@ import type { User } from '@db/entities/User';
|
|||
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||
import { validateEntity } from '@/GenericHelpers';
|
||||
import { ExternalHooks } from '@/ExternalHooks';
|
||||
import { type WorkflowRequest, hasSharing, type ListQuery } from '@/requests';
|
||||
import { hasSharing, type ListQuery } from '@/requests';
|
||||
import type { WorkflowRequest } from '@/workflows/workflow.request';
|
||||
import { TagService } from '@/services/tag.service';
|
||||
import type { IWorkflowDb, IWorkflowExecutionDataProcess } from '@/Interfaces';
|
||||
import { NodeTypes } from '@/NodeTypes';
|
||||
|
|
|
@ -6,17 +6,17 @@ import * as Db from '@/Db';
|
|||
import * as GenericHelpers from '@/GenericHelpers';
|
||||
import * as ResponseHelper from '@/ResponseHelper';
|
||||
import * as WorkflowHelpers from '@/WorkflowHelpers';
|
||||
import type { IWorkflowResponse, IExecutionPushResponse } from '@/Interfaces';
|
||||
import type { IWorkflowResponse } from '@/Interfaces';
|
||||
import config from '@/config';
|
||||
import { SharedWorkflow } from '@db/entities/SharedWorkflow';
|
||||
import { WorkflowEntity } from '@db/entities/WorkflowEntity';
|
||||
import { validateEntity } from '@/GenericHelpers';
|
||||
import { ExternalHooks } from '@/ExternalHooks';
|
||||
import type { ListQuery, WorkflowRequest } from '@/requests';
|
||||
import { ListQuery } from '@/requests';
|
||||
import { isBelowOnboardingThreshold } from '@/WorkflowHelpers';
|
||||
import { WorkflowService } from './workflow.service';
|
||||
import { isSharingEnabled, rightDiff } from '@/UserManagement/UserManagementHelper';
|
||||
import { Container } from 'typedi';
|
||||
import { isSharingEnabled } from '@/UserManagement/UserManagementHelper';
|
||||
import Container, { Service } from 'typedi';
|
||||
import { InternalHooks } from '@/InternalHooks';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import * as utils from '@/utils';
|
||||
|
@ -36,15 +36,31 @@ import type { RoleNames } from '@/databases/entities/Role';
|
|||
import { UnauthorizedError } from '@/errors/response-errors/unauthorized.error';
|
||||
import { CredentialsService } from '../credentials/credentials.service';
|
||||
import { UserRepository } from '@/databases/repositories/user.repository';
|
||||
import { Authorized, Delete, Get, Patch, Post, Put, RestController } from '@/decorators';
|
||||
import { WorkflowRequest } from './workflow.request';
|
||||
|
||||
export const workflowsController = express.Router();
|
||||
@Service()
|
||||
@Authorized()
|
||||
@RestController('/workflows')
|
||||
export class WorkflowsController {
|
||||
constructor(
|
||||
private readonly logger: Logger,
|
||||
private readonly internalHooks: InternalHooks,
|
||||
private readonly externalHooks: ExternalHooks,
|
||||
private readonly tagRepository: TagRepository,
|
||||
private readonly enterpriseWorkflowService: EnterpriseWorkflowService,
|
||||
private readonly roleService: RoleService,
|
||||
private readonly workflowHistoryService: WorkflowHistoryService,
|
||||
private readonly tagService: TagService,
|
||||
private readonly namingService: NamingService,
|
||||
private readonly workflowRepository: WorkflowRepository,
|
||||
private readonly workflowService: WorkflowService,
|
||||
private readonly sharedWorkflowRepository: SharedWorkflowRepository,
|
||||
private readonly userRepository: UserRepository,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* POST /workflows
|
||||
*/
|
||||
workflowsController.post(
|
||||
'/',
|
||||
ResponseHelper.send(async (req: WorkflowRequest.Create) => {
|
||||
@Post('/')
|
||||
async create(req: WorkflowRequest.Create) {
|
||||
delete req.body.id; // delete if sent
|
||||
|
||||
const newWorkflow = new WorkflowEntity();
|
||||
|
@ -55,12 +71,12 @@ workflowsController.post(
|
|||
|
||||
await validateEntity(newWorkflow);
|
||||
|
||||
await Container.get(ExternalHooks).run('workflow.create', [newWorkflow]);
|
||||
await this.externalHooks.run('workflow.create', [newWorkflow]);
|
||||
|
||||
const { tags: tagIds } = req.body;
|
||||
|
||||
if (tagIds?.length && !config.getEnv('workflowTagsDisabled')) {
|
||||
newWorkflow.tags = await Container.get(TagRepository).findMany(tagIds);
|
||||
newWorkflow.tags = await this.tagRepository.findMany(tagIds);
|
||||
}
|
||||
|
||||
await WorkflowHelpers.replaceInvalidCredentials(newWorkflow);
|
||||
|
@ -74,7 +90,7 @@ workflowsController.post(
|
|||
const allCredentials = await CredentialsService.getMany(req.user);
|
||||
|
||||
try {
|
||||
Container.get(EnterpriseWorkflowService).validateCredentialPermissionsToUser(
|
||||
this.enterpriseWorkflowService.validateCredentialPermissionsToUser(
|
||||
newWorkflow,
|
||||
allCredentials,
|
||||
);
|
||||
|
@ -90,7 +106,7 @@ workflowsController.post(
|
|||
await Db.transaction(async (transactionManager) => {
|
||||
savedWorkflow = await transactionManager.save<WorkflowEntity>(newWorkflow);
|
||||
|
||||
const role = await Container.get(RoleService).findWorkflowOwnerRole();
|
||||
const role = await this.roleService.findWorkflowOwnerRole();
|
||||
|
||||
const newSharedWorkflow = new SharedWorkflow();
|
||||
|
||||
|
@ -104,36 +120,26 @@ workflowsController.post(
|
|||
});
|
||||
|
||||
if (!savedWorkflow) {
|
||||
Container.get(Logger).error('Failed to create workflow', { userId: req.user.id });
|
||||
this.logger.error('Failed to create workflow', { userId: req.user.id });
|
||||
throw new InternalServerError('Failed to save workflow');
|
||||
}
|
||||
|
||||
await Container.get(WorkflowHistoryService).saveVersion(
|
||||
req.user,
|
||||
savedWorkflow,
|
||||
savedWorkflow.id,
|
||||
);
|
||||
await this.workflowHistoryService.saveVersion(req.user, savedWorkflow, savedWorkflow.id);
|
||||
|
||||
if (tagIds && !config.getEnv('workflowTagsDisabled') && savedWorkflow.tags) {
|
||||
savedWorkflow.tags = Container.get(TagService).sortByRequestOrder(savedWorkflow.tags, {
|
||||
savedWorkflow.tags = this.tagService.sortByRequestOrder(savedWorkflow.tags, {
|
||||
requestOrder: tagIds,
|
||||
});
|
||||
}
|
||||
|
||||
await Container.get(ExternalHooks).run('workflow.afterCreate', [savedWorkflow]);
|
||||
void Container.get(InternalHooks).onWorkflowCreated(req.user, newWorkflow, false);
|
||||
await this.externalHooks.run('workflow.afterCreate', [savedWorkflow]);
|
||||
void this.internalHooks.onWorkflowCreated(req.user, newWorkflow, false);
|
||||
|
||||
return savedWorkflow;
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /workflows
|
||||
*/
|
||||
workflowsController.get(
|
||||
'/',
|
||||
listQueryMiddleware,
|
||||
async (req: ListQuery.Request, res: express.Response) => {
|
||||
@Get('/', { middlewares: listQueryMiddleware })
|
||||
async getAll(req: ListQuery.Request, res: express.Response) {
|
||||
try {
|
||||
const roles: RoleNames[] = isSharingEnabled() ? [] : ['owner'];
|
||||
const sharedWorkflowIds = await WorkflowHelpers.getSharedWorkflowIds(req.user, roles);
|
||||
|
@ -149,18 +155,13 @@ workflowsController.get(
|
|||
ResponseHelper.reportError(error);
|
||||
ResponseHelper.sendErrorResponse(res, error);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /workflows/new
|
||||
*/
|
||||
workflowsController.get(
|
||||
'/new',
|
||||
ResponseHelper.send(async (req: WorkflowRequest.NewName) => {
|
||||
@Get('/new')
|
||||
async getNewName(req: WorkflowRequest.NewName) {
|
||||
const requestedName = req.query.name ?? config.getEnv('workflows.defaultName');
|
||||
|
||||
const name = await Container.get(NamingService).getUniqueWorkflowName(requestedName);
|
||||
const name = await this.namingService.getUniqueWorkflowName(requestedName);
|
||||
|
||||
const onboardingFlowEnabled =
|
||||
!config.getEnv('workflows.onboardingFlowDisabled') &&
|
||||
|
@ -168,27 +169,21 @@ workflowsController.get(
|
|||
(await isBelowOnboardingThreshold(req.user));
|
||||
|
||||
return { name, onboardingFlowEnabled };
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
// Reads and returns workflow data from an URL
|
||||
/**
|
||||
* GET /workflows/from-url
|
||||
*/
|
||||
workflowsController.get(
|
||||
'/from-url',
|
||||
ResponseHelper.send(async (req: express.Request): Promise<IWorkflowResponse> => {
|
||||
@Get('/from-url')
|
||||
async getFromUrl(req: WorkflowRequest.FromUrl) {
|
||||
if (req.query.url === undefined) {
|
||||
throw new BadRequestError('The parameter "url" is missing!');
|
||||
}
|
||||
if (!/^http[s]?:\/\/.*\.json$/i.exec(req.query.url as string)) {
|
||||
if (!/^http[s]?:\/\/.*\.json$/i.exec(req.query.url)) {
|
||||
throw new BadRequestError(
|
||||
'The parameter "url" is not valid! It does not seem to be a URL pointing to a n8n workflow JSON file.',
|
||||
);
|
||||
}
|
||||
let workflowData: IWorkflowResponse | undefined;
|
||||
try {
|
||||
const { data } = await axios.get<IWorkflowResponse>(req.query.url as string);
|
||||
const { data } = await axios.get<IWorkflowResponse>(req.query.url);
|
||||
workflowData = data;
|
||||
} catch (error) {
|
||||
throw new BadRequestError('The URL does not point to valid JSON file!');
|
||||
|
@ -208,15 +203,10 @@ workflowsController.get(
|
|||
}
|
||||
|
||||
return workflowData;
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /workflows/:id
|
||||
*/
|
||||
workflowsController.get(
|
||||
'/:id(\\w+)',
|
||||
ResponseHelper.send(async (req: WorkflowRequest.Get) => {
|
||||
@Get('/:id')
|
||||
async getWorkflow(req: WorkflowRequest.Get) {
|
||||
const { id: workflowId } = req.params;
|
||||
|
||||
if (isSharingEnabled()) {
|
||||
|
@ -225,10 +215,7 @@ workflowsController.get(
|
|||
relations.push('tags');
|
||||
}
|
||||
|
||||
const workflow = await Container.get(WorkflowRepository).get(
|
||||
{ id: workflowId },
|
||||
{ relations },
|
||||
);
|
||||
const workflow = await this.workflowRepository.get({ id: workflowId }, { relations });
|
||||
|
||||
if (!workflow) {
|
||||
throw new NotFoundError(`Workflow with ID "${workflowId}" does not exist`);
|
||||
|
@ -241,7 +228,7 @@ workflowsController.get(
|
|||
);
|
||||
}
|
||||
|
||||
const enterpriseWorkflowService = Container.get(EnterpriseWorkflowService);
|
||||
const enterpriseWorkflowService = this.enterpriseWorkflowService;
|
||||
|
||||
enterpriseWorkflowService.addOwnerAndSharings(workflow);
|
||||
await enterpriseWorkflowService.addCredentialsToWorkflow(workflow, req.user);
|
||||
|
@ -252,7 +239,7 @@ workflowsController.get(
|
|||
|
||||
const extraRelations = config.getEnv('workflowTagsDisabled') ? [] : ['workflow.tags'];
|
||||
|
||||
const shared = await Container.get(SharedWorkflowRepository).findSharing(
|
||||
const shared = await this.sharedWorkflowRepository.findSharing(
|
||||
workflowId,
|
||||
req.user,
|
||||
'workflow:read',
|
||||
|
@ -260,7 +247,7 @@ workflowsController.get(
|
|||
);
|
||||
|
||||
if (!shared) {
|
||||
Container.get(Logger).verbose('User attempted to access a workflow without permissions', {
|
||||
this.logger.verbose('User attempted to access a workflow without permissions', {
|
||||
workflowId,
|
||||
userId: req.user.id,
|
||||
});
|
||||
|
@ -270,16 +257,10 @@ workflowsController.get(
|
|||
}
|
||||
|
||||
return shared.workflow;
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
// Updates an existing workflow
|
||||
/**
|
||||
* PATCH /workflows/:id
|
||||
*/
|
||||
workflowsController.patch(
|
||||
'/:id(\\w+)',
|
||||
ResponseHelper.send(async (req: WorkflowRequest.Update) => {
|
||||
@Patch('/:id')
|
||||
async update(req: WorkflowRequest.Update) {
|
||||
const { id: workflowId } = req.params;
|
||||
const forceSave = req.query.forceSave === 'true';
|
||||
|
||||
|
@ -288,14 +269,14 @@ workflowsController.patch(
|
|||
Object.assign(updateData, rest);
|
||||
|
||||
if (isSharingEnabled()) {
|
||||
updateData = await Container.get(EnterpriseWorkflowService).preventTampering(
|
||||
updateData = await this.enterpriseWorkflowService.preventTampering(
|
||||
updateData,
|
||||
workflowId,
|
||||
req.user,
|
||||
);
|
||||
}
|
||||
|
||||
const updatedWorkflow = await Container.get(WorkflowService).update(
|
||||
const updatedWorkflow = await this.workflowService.update(
|
||||
req.user,
|
||||
updateData,
|
||||
workflowId,
|
||||
|
@ -305,21 +286,15 @@ workflowsController.patch(
|
|||
);
|
||||
|
||||
return updatedWorkflow;
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
// Deletes a specific workflow
|
||||
/**
|
||||
* DELETE /workflows/:id
|
||||
*/
|
||||
workflowsController.delete(
|
||||
'/:id(\\w+)',
|
||||
ResponseHelper.send(async (req: WorkflowRequest.Delete) => {
|
||||
@Delete('/:id')
|
||||
async delete(req: WorkflowRequest.Delete) {
|
||||
const { id: workflowId } = req.params;
|
||||
|
||||
const workflow = await Container.get(WorkflowService).delete(req.user, workflowId);
|
||||
const workflow = await this.workflowService.delete(req.user, workflowId);
|
||||
if (!workflow) {
|
||||
Container.get(Logger).verbose('User attempted to delete a workflow without permissions', {
|
||||
this.logger.verbose('User attempted to delete a workflow without permissions', {
|
||||
workflowId,
|
||||
userId: req.user.id,
|
||||
});
|
||||
|
@ -329,20 +304,15 @@ workflowsController.delete(
|
|||
}
|
||||
|
||||
return true;
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /workflows/run
|
||||
*/
|
||||
workflowsController.post(
|
||||
'/run',
|
||||
ResponseHelper.send(async (req: WorkflowRequest.ManualRun): Promise<IExecutionPushResponse> => {
|
||||
@Post('/run')
|
||||
async runManually(req: WorkflowRequest.ManualRun) {
|
||||
if (isSharingEnabled()) {
|
||||
const workflow = Container.get(WorkflowRepository).create(req.body.workflowData);
|
||||
const workflow = this.workflowRepository.create(req.body.workflowData);
|
||||
|
||||
if (req.body.workflowData.id !== undefined) {
|
||||
const safeWorkflow = await Container.get(EnterpriseWorkflowService).preventTampering(
|
||||
const safeWorkflow = await this.enterpriseWorkflowService.preventTampering(
|
||||
workflow,
|
||||
workflow.id,
|
||||
req.user,
|
||||
|
@ -351,22 +321,11 @@ workflowsController.post(
|
|||
}
|
||||
}
|
||||
|
||||
return Container.get(WorkflowService).runManually(
|
||||
req.body,
|
||||
req.user,
|
||||
GenericHelpers.getSessionId(req),
|
||||
);
|
||||
}),
|
||||
);
|
||||
return this.workflowService.runManually(req.body, req.user, GenericHelpers.getSessionId(req));
|
||||
}
|
||||
|
||||
/**
|
||||
* (EE) PUT /workflows/:id/share
|
||||
*
|
||||
* Grant or remove users' access to a workflow.
|
||||
*/
|
||||
workflowsController.put(
|
||||
'/:workflowId/share',
|
||||
ResponseHelper.send(async (req: WorkflowRequest.Share) => {
|
||||
@Put('/:workflowId/share')
|
||||
async share(req: WorkflowRequest.Share) {
|
||||
if (!isSharingEnabled()) throw new NotFoundError('Route not found');
|
||||
|
||||
const { workflowId } = req.params;
|
||||
|
@ -379,7 +338,7 @@ workflowsController.put(
|
|||
throw new BadRequestError('Bad request');
|
||||
}
|
||||
|
||||
const isOwnedRes = await Container.get(EnterpriseWorkflowService).isOwned(req.user, workflowId);
|
||||
const isOwnedRes = await this.enterpriseWorkflowService.isOwned(req.user, workflowId);
|
||||
const { ownsWorkflow } = isOwnedRes;
|
||||
let { workflow } = isOwnedRes;
|
||||
|
||||
|
@ -387,14 +346,10 @@ workflowsController.put(
|
|||
workflow = undefined;
|
||||
// Allow owners/admins to share
|
||||
if (req.user.hasGlobalScope('workflow:share')) {
|
||||
const sharedRes = await Container.get(SharedWorkflowRepository).getSharing(
|
||||
req.user,
|
||||
workflowId,
|
||||
{
|
||||
allowGlobalScope: true,
|
||||
globalScope: 'workflow:share',
|
||||
},
|
||||
);
|
||||
const sharedRes = await this.sharedWorkflowRepository.getSharing(req.user, workflowId, {
|
||||
allowGlobalScope: true,
|
||||
globalScope: 'workflow:share',
|
||||
});
|
||||
workflow = sharedRes?.workflow;
|
||||
}
|
||||
if (!workflow) {
|
||||
|
@ -403,7 +358,7 @@ workflowsController.put(
|
|||
}
|
||||
|
||||
const ownerIds = (
|
||||
await Container.get(WorkflowRepository).getSharings(
|
||||
await this.workflowRepository.getSharings(
|
||||
Db.getConnection().createEntityManager(),
|
||||
workflowId,
|
||||
['shared', 'shared.role'],
|
||||
|
@ -415,31 +370,24 @@ workflowsController.put(
|
|||
let newShareeIds: string[] = [];
|
||||
await Db.transaction(async (trx) => {
|
||||
// remove all sharings that are not supposed to exist anymore
|
||||
await Container.get(WorkflowRepository).pruneSharings(trx, workflowId, [
|
||||
...ownerIds,
|
||||
...shareWithIds,
|
||||
]);
|
||||
await this.workflowRepository.pruneSharings(trx, workflowId, [...ownerIds, ...shareWithIds]);
|
||||
|
||||
const sharings = await Container.get(WorkflowRepository).getSharings(trx, workflowId);
|
||||
const sharings = await this.workflowRepository.getSharings(trx, workflowId);
|
||||
|
||||
// extract the new sharings that need to be added
|
||||
newShareeIds = rightDiff(
|
||||
newShareeIds = utils.rightDiff(
|
||||
[sharings, (sharing) => sharing.userId],
|
||||
[shareWithIds, (shareeId) => shareeId],
|
||||
);
|
||||
|
||||
if (newShareeIds.length) {
|
||||
const users = await Container.get(UserRepository).getByIds(trx, newShareeIds);
|
||||
const role = await Container.get(RoleService).findWorkflowEditorRole();
|
||||
const users = await this.userRepository.getByIds(trx, newShareeIds);
|
||||
const role = await this.roleService.findWorkflowEditorRole();
|
||||
|
||||
await Container.get(SharedWorkflowRepository).share(trx, workflow!, users, role.id);
|
||||
await this.sharedWorkflowRepository.share(trx, workflow!, users, role.id);
|
||||
}
|
||||
});
|
||||
|
||||
void Container.get(InternalHooks).onWorkflowSharingUpdate(
|
||||
workflowId,
|
||||
req.user.id,
|
||||
shareWithIds,
|
||||
);
|
||||
}),
|
||||
);
|
||||
void this.internalHooks.onWorkflowSharingUpdate(workflowId, req.user.id, shareWithIds);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -126,8 +126,8 @@ export const setupTestServer = ({
|
|||
break;
|
||||
|
||||
case 'workflows':
|
||||
const { workflowsController } = await import('@/workflows/workflows.controller');
|
||||
app.use(`/${REST_PATH_SEGMENT}/workflows`, workflowsController);
|
||||
const { WorkflowsController } = await import('@/workflows/workflows.controller');
|
||||
registerController(app, WorkflowsController);
|
||||
break;
|
||||
|
||||
case 'executions':
|
||||
|
|
Loading…
Reference in a new issue