diff --git a/packages/cli/src/Server.ts b/packages/cli/src/Server.ts index 708012d1a1..597bbbc17c 100644 --- a/packages/cli/src/Server.ts +++ b/packages/cli/src/Server.ts @@ -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 // ---------------------------------------- diff --git a/packages/cli/src/UserManagement/UserManagementHelper.ts b/packages/cli/src/UserManagement/UserManagementHelper.ts index 4178dff009..97557c45f9 100644 --- a/packages/cli/src/UserManagement/UserManagementHelper.ts +++ b/packages/cli/src/UserManagement/UserManagementHelper.ts @@ -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( - [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((acc, item) => { - if (!keyMap[keyExtractor2(item)]) { - acc.push(item); - } - return acc; - }, []); -} diff --git a/packages/cli/src/controllers/activeWorkflows.controller.ts b/packages/cli/src/controllers/activeWorkflows.controller.ts index 323ec018a4..6e37b40b86 100644 --- a/packages/cli/src/controllers/activeWorkflows.controller.ts +++ b/packages/cli/src/controllers/activeWorkflows.controller.ts @@ -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 }, diff --git a/packages/cli/src/credentials/credentials.controller.ee.ts b/packages/cli/src/credentials/credentials.controller.ee.ts index 8524996efd..eb4fd7ee4a 100644 --- a/packages/cli/src/credentials/credentials.controller.ee.ts +++ b/packages/cli/src/credentials/credentials.controller.ee.ts @@ -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], ); diff --git a/packages/cli/src/requests.ts b/packages/cli/src/requests.ts index e7f9c33484..641d1c72fd 100644 --- a/packages/cli/src/requests.ts +++ b/packages/cli/src/requests.ts @@ -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; - }>; - - 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 }>; +} diff --git a/packages/cli/src/utils.ts b/packages/cli/src/utils.ts index 4934a01d1e..72d020e96d 100644 --- a/packages/cli/src/utils.ts +++ b/packages/cli/src/utils.ts @@ -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( + [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((acc, item) => { + if (!keyMap[keyExtractor2(item)]) { + acc.push(item); + } + return acc; + }, []); +} diff --git a/packages/cli/src/workflows/workflow.request.ts b/packages/cli/src/workflows/workflow.request.ts new file mode 100644 index 0000000000..e576f50f36 --- /dev/null +++ b/packages/cli/src/workflows/workflow.request.ts @@ -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; + }>; + + 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 }>; +} diff --git a/packages/cli/src/workflows/workflow.service.ts b/packages/cli/src/workflows/workflow.service.ts index 1c97e72a59..a216470d94 100644 --- a/packages/cli/src/workflows/workflow.service.ts +++ b/packages/cli/src/workflows/workflow.service.ts @@ -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'; diff --git a/packages/cli/src/workflows/workflows.controller.ts b/packages/cli/src/workflows/workflows.controller.ts index 756328c03b..c38fa32fb6 100644 --- a/packages/cli/src/workflows/workflows.controller.ts +++ b/packages/cli/src/workflows/workflows.controller.ts @@ -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(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 => { + @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(req.query.url as string); + const { data } = await axios.get(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 => { + @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); + } +} diff --git a/packages/cli/test/integration/shared/utils/testServer.ts b/packages/cli/test/integration/shared/utils/testServer.ts index 9f85e4c487..d77eca67ce 100644 --- a/packages/cli/test/integration/shared/utils/testServer.ts +++ b/packages/cli/test/integration/shared/utils/testServer.ts @@ -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':