diff --git a/packages/backend/src/models/step.js b/packages/backend/src/models/step.js index 6bfd26ed..9f5f3f70 100644 --- a/packages/backend/src/models/step.js +++ b/packages/backend/src/models/step.js @@ -314,13 +314,13 @@ class Step extends Base { } async updateFor(user, newStepData) { - const { connectionId, appKey, key, parameters } = newStepData; + const { appKey = this.appKey, connectionId, key, parameters } = newStepData; - if (connectionId && (appKey || this.appKey)) { + if (connectionId && appKey) { await user.authorizedConnections .findOne({ id: connectionId, - key: appKey || this.appKey, + key: appKey, }) .throwIfNotFound(); } @@ -334,8 +334,8 @@ class Step extends Base { } const updatedStep = await this.$query().patchAndFetch({ - key: key, - appKey: appKey, + key, + appKey, connectionId: connectionId, parameters: parameters, status: 'incomplete', diff --git a/packages/backend/src/models/step.test.js b/packages/backend/src/models/step.test.js index 9a7bd785..f8ece82e 100644 --- a/packages/backend/src/models/step.test.js +++ b/packages/backend/src/models/step.test.js @@ -1,4 +1,4 @@ -import { describe, it, expect, vi } from 'vitest'; +import { beforeEach, describe, it, expect, vi } from 'vitest'; import appConfig from '../config/app.js'; import App from './app.js'; import Base from './base.js'; @@ -9,6 +9,10 @@ import ExecutionStep from './execution-step.js'; import Telemetry from '../helpers/telemetry/index.js'; import * as testRunModule from '../services/test-run.js'; import { createFlow } from '../../test/factories/flow.js'; +import { createUser } from '../../test/factories/user.js'; +import { createRole } from '../../test/factories/role.js'; +import { createPermission } from '../../test/factories/permission.js'; +import { createConnection } from '../../test/factories/connection.js'; import { createStep } from '../../test/factories/step.js'; import { createExecutionStep } from '../../test/factories/execution-step.js'; @@ -353,6 +357,107 @@ describe('Step model', () => { }); }); + describe('updateFor', async () => { + let step, + userRole, + user, + userConnection, + anotherUser, + anotherUserConnection; + + beforeEach(async () => { + userRole = await createRole({ name: 'User' }); + anotherUser = await createUser({ roleId: userRole.id }); + user = await createUser({ roleId: userRole.id }); + + userConnection = await createConnection({ + key: 'deepl', + userId: user.id, + }); + + anotherUserConnection = await createConnection({ + key: 'deepl', + userId: anotherUser.id, + }); + + await createPermission({ + roleId: userRole.id, + action: 'read', + subject: 'Connection', + conditions: ['isCreator'], + }); + + step = await createStep(); + }); + + it('should update step with the given payload and mark it as incomplete', async () => { + const stepData = { + appKey: 'deepl', + key: 'translateText', + connectionId: anotherUserConnection.id, + parameters: { + key: 'value', + }, + }; + + const anotherUserWithRoleAndPermissions = await anotherUser + .$query() + .withGraphFetched({ permissions: true, role: true }); + + const updatedStep = await step.updateFor( + anotherUserWithRoleAndPermissions, + stepData + ); + + expect(updatedStep).toMatchObject({ + ...stepData, + status: 'incomplete', + }); + }); + + it('should invoke updateWebhookUrl', async () => { + const updateWebhookUrlSpy = vi + .spyOn(Step.prototype, 'updateWebhookUrl') + .mockResolvedValue(); + + const stepData = { + appKey: 'deepl', + key: 'translateText', + }; + + await step.updateFor(user, stepData); + + expect(updateWebhookUrlSpy).toHaveBeenCalledOnce(); + }); + + it('should not update step when inaccessible connection is given', async () => { + const stepData = { + appKey: 'deepl', + key: 'translateText', + connectionId: userConnection.id, + }; + + const anotherUserWithRoleAndPermissions = await anotherUser + .$query() + .withGraphFetched({ permissions: true, role: true }); + + await expect(() => + step.updateFor(anotherUserWithRoleAndPermissions, stepData) + ).rejects.toThrowError('NotFoundError'); + }); + + it('should not update step when given app key and key do not exist', async () => { + const stepData = { + appKey: 'deepl', + key: 'not-existing-key', + }; + + await expect(() => step.updateFor(user, stepData)).rejects.toThrowError( + 'DeepL does not have an action with the "not-existing-key" key!' + ); + }); + }); + describe('$afterInsert', () => { it('should call super.$afterInsert', async () => { const superAfterInsertSpy = vi.spyOn(Base.prototype, '$afterInsert'); diff --git a/packages/backend/test/factories/role.js b/packages/backend/test/factories/role.js index 28ac9960..34023c7b 100644 --- a/packages/backend/test/factories/role.js +++ b/packages/backend/test/factories/role.js @@ -1,5 +1,5 @@ import { faker } from '@faker-js/faker'; -import Role from '../../src/models/role'; +import Role from '../../src/models/role.js'; export const createRole = async (params = {}) => { const name = faker.lorem.word();