feat: Implement rest API endpoint to delete flow
This commit is contained in:
10
packages/backend/src/controllers/api/v1/flows/delete-flow.js
Normal file
10
packages/backend/src/controllers/api/v1/flows/delete-flow.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
export default async (request, response) => {
|
||||||
|
const flow = await request.currentUser.authorizedFlows
|
||||||
|
.clone()
|
||||||
|
.findById(request.params.flowId)
|
||||||
|
.throwIfNotFound();
|
||||||
|
|
||||||
|
await flow.delete();
|
||||||
|
|
||||||
|
response.status(204).end();
|
||||||
|
};
|
@@ -0,0 +1,110 @@
|
|||||||
|
import { describe, it, beforeEach } from 'vitest';
|
||||||
|
import request from 'supertest';
|
||||||
|
import Crypto from 'crypto';
|
||||||
|
import app from '../../../../app.js';
|
||||||
|
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id.js';
|
||||||
|
import { createUser } from '../../../../../test/factories/user.js';
|
||||||
|
import { createFlow } from '../../../../../test/factories/flow.js';
|
||||||
|
import { createPermission } from '../../../../../test/factories/permission.js';
|
||||||
|
|
||||||
|
describe('DELETE /api/v1/flows/:flowId', () => {
|
||||||
|
let currentUser, currentUserRole, token;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
currentUser = await createUser();
|
||||||
|
currentUserRole = await currentUser.$relatedQuery('role');
|
||||||
|
|
||||||
|
token = await createAuthTokenByUserId(currentUser.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remove the current user flow and return no content', async () => {
|
||||||
|
const currentUserFlow = await createFlow({ userId: currentUser.id });
|
||||||
|
|
||||||
|
await createPermission({
|
||||||
|
action: 'read',
|
||||||
|
subject: 'Flow',
|
||||||
|
roleId: currentUserRole.id,
|
||||||
|
conditions: ['isCreator'],
|
||||||
|
});
|
||||||
|
|
||||||
|
await createPermission({
|
||||||
|
action: 'delete',
|
||||||
|
subject: 'Flow',
|
||||||
|
roleId: currentUserRole.id,
|
||||||
|
conditions: ['isCreator'],
|
||||||
|
});
|
||||||
|
|
||||||
|
await request(app)
|
||||||
|
.delete(`/api/v1/flows/${currentUserFlow.id}`)
|
||||||
|
.set('Authorization', token)
|
||||||
|
.expect(204);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remove another user flow and return no content', async () => {
|
||||||
|
const anotherUser = await createUser();
|
||||||
|
const anotherUserFlow = await createFlow({ userId: anotherUser.id });
|
||||||
|
|
||||||
|
await createPermission({
|
||||||
|
action: 'read',
|
||||||
|
subject: 'Flow',
|
||||||
|
roleId: currentUserRole.id,
|
||||||
|
conditions: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
await createPermission({
|
||||||
|
action: 'delete',
|
||||||
|
subject: 'Flow',
|
||||||
|
roleId: currentUserRole.id,
|
||||||
|
conditions: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
await request(app)
|
||||||
|
.delete(`/api/v1/flows/${anotherUserFlow.id}`)
|
||||||
|
.set('Authorization', token)
|
||||||
|
.expect(204);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return not found response for not existing flow UUID', async () => {
|
||||||
|
await createPermission({
|
||||||
|
action: 'read',
|
||||||
|
subject: 'Flow',
|
||||||
|
roleId: currentUserRole.id,
|
||||||
|
conditions: ['isCreator'],
|
||||||
|
});
|
||||||
|
|
||||||
|
await createPermission({
|
||||||
|
action: 'delete',
|
||||||
|
subject: 'Flow',
|
||||||
|
roleId: currentUserRole.id,
|
||||||
|
conditions: ['isCreator'],
|
||||||
|
});
|
||||||
|
|
||||||
|
const notExistingFlowUUID = Crypto.randomUUID();
|
||||||
|
|
||||||
|
await request(app)
|
||||||
|
.delete(`/api/v1/flows/${notExistingFlowUUID}`)
|
||||||
|
.set('Authorization', token)
|
||||||
|
.expect(404);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return bad request response for invalid UUID', async () => {
|
||||||
|
await createPermission({
|
||||||
|
action: 'read',
|
||||||
|
subject: 'Flow',
|
||||||
|
roleId: currentUserRole.id,
|
||||||
|
conditions: ['isCreator'],
|
||||||
|
});
|
||||||
|
|
||||||
|
await createPermission({
|
||||||
|
action: 'delete',
|
||||||
|
subject: 'Flow',
|
||||||
|
roleId: currentUserRole.id,
|
||||||
|
conditions: ['isCreator'],
|
||||||
|
});
|
||||||
|
|
||||||
|
await request(app)
|
||||||
|
.delete('/api/v1/flows/invalidFlowUUID')
|
||||||
|
.set('Authorization', token)
|
||||||
|
.expect(400);
|
||||||
|
});
|
||||||
|
});
|
@@ -25,6 +25,10 @@ const authorizationList = {
|
|||||||
action: 'create',
|
action: 'create',
|
||||||
subject: 'Flow',
|
subject: 'Flow',
|
||||||
},
|
},
|
||||||
|
'DELETE /api/v1/flows/:flowId': {
|
||||||
|
action: 'delete',
|
||||||
|
subject: 'Flow',
|
||||||
|
},
|
||||||
'GET /api/v1/steps/:stepId/connection': {
|
'GET /api/v1/steps/:stepId/connection': {
|
||||||
action: 'read',
|
action: 'read',
|
||||||
subject: 'Flow',
|
subject: 'Flow',
|
||||||
|
@@ -3,6 +3,9 @@ import Base from './base.js';
|
|||||||
import Step from './step.js';
|
import Step from './step.js';
|
||||||
import User from './user.js';
|
import User from './user.js';
|
||||||
import Execution from './execution.js';
|
import Execution from './execution.js';
|
||||||
|
import ExecutionStep from './execution-step.js';
|
||||||
|
import globalVariable from '../helpers/global-variable.js';
|
||||||
|
import logger from '../helpers/logger.js';
|
||||||
import Telemetry from '../helpers/telemetry/index.js';
|
import Telemetry from '../helpers/telemetry/index.js';
|
||||||
|
|
||||||
class Flow extends Base {
|
class Flow extends Base {
|
||||||
@@ -160,6 +163,39 @@ class Flow extends Base {
|
|||||||
return createdStep;
|
return createdStep;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async delete() {
|
||||||
|
const triggerStep = await this.getTriggerStep();
|
||||||
|
const trigger = await triggerStep?.getTriggerCommand();
|
||||||
|
|
||||||
|
if (trigger?.type === 'webhook' && trigger.unregisterHook) {
|
||||||
|
const $ = await globalVariable({
|
||||||
|
flow: this,
|
||||||
|
connection: await triggerStep.$relatedQuery('connection'),
|
||||||
|
app: await triggerStep.getApp(),
|
||||||
|
step: triggerStep,
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
await trigger.unregisterHook($);
|
||||||
|
} catch (error) {
|
||||||
|
// suppress error as the remote resource might have been already deleted
|
||||||
|
logger.debug(
|
||||||
|
`Failed to unregister webhook for flow ${this.id}: ${error.message}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const executionIds = (
|
||||||
|
await this.$relatedQuery('executions').select('executions.id')
|
||||||
|
).map((execution) => execution.id);
|
||||||
|
|
||||||
|
await ExecutionStep.query().delete().whereIn('execution_id', executionIds);
|
||||||
|
|
||||||
|
await this.$relatedQuery('executions').delete();
|
||||||
|
await this.$relatedQuery('steps').delete();
|
||||||
|
await this.$query().delete();
|
||||||
|
}
|
||||||
|
|
||||||
async $beforeUpdate(opt, queryContext) {
|
async $beforeUpdate(opt, queryContext) {
|
||||||
await super.$beforeUpdate(opt, queryContext);
|
await super.$beforeUpdate(opt, queryContext);
|
||||||
|
|
||||||
|
@@ -6,6 +6,7 @@ import getFlowAction from '../../../controllers/api/v1/flows/get-flow.js';
|
|||||||
import updateFlowAction from '../../../controllers/api/v1/flows/update-flow.js';
|
import updateFlowAction from '../../../controllers/api/v1/flows/update-flow.js';
|
||||||
import createFlowAction from '../../../controllers/api/v1/flows/create-flow.js';
|
import createFlowAction from '../../../controllers/api/v1/flows/create-flow.js';
|
||||||
import createStepAction from '../../../controllers/api/v1/flows/create-step.js';
|
import createStepAction from '../../../controllers/api/v1/flows/create-step.js';
|
||||||
|
import deleteFlowAction from '../../../controllers/api/v1/flows/delete-flow.js';
|
||||||
|
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
@@ -13,6 +14,7 @@ router.get('/', authenticateUser, authorizeUser, getFlowsAction);
|
|||||||
router.get('/:flowId', authenticateUser, authorizeUser, getFlowAction);
|
router.get('/:flowId', authenticateUser, authorizeUser, getFlowAction);
|
||||||
router.post('/', authenticateUser, authorizeUser, createFlowAction);
|
router.post('/', authenticateUser, authorizeUser, createFlowAction);
|
||||||
router.patch('/:flowId', authenticateUser, authorizeUser, updateFlowAction);
|
router.patch('/:flowId', authenticateUser, authorizeUser, updateFlowAction);
|
||||||
|
|
||||||
router.post(
|
router.post(
|
||||||
'/:flowId/steps',
|
'/:flowId/steps',
|
||||||
authenticateUser,
|
authenticateUser,
|
||||||
@@ -20,4 +22,6 @@ router.post(
|
|||||||
createStepAction
|
createStepAction
|
||||||
);
|
);
|
||||||
|
|
||||||
|
router.delete('/:flowId', authenticateUser, authorizeUser, deleteFlowAction);
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
Reference in New Issue
Block a user