Merge pull request #2032 from automatisch/rest-delete-step

feat: Implement delete step rest API endpoint
This commit is contained in:
Ömer Faruk Aydın
2024-08-23 17:44:23 +03:00
committed by GitHub
6 changed files with 178 additions and 2 deletions

View File

@@ -11,5 +11,5 @@ export default async (request, response) => {
await accessToken.revoke();
response.status(204).send();
response.status(204).end();
};

View File

@@ -0,0 +1,9 @@
export default async (request, response) => {
const step = await request.currentUser.authorizedSteps
.findById(request.params.stepId)
.throwIfNotFound();
await step.delete();
response.status(204).end();
};

View File

@@ -0,0 +1,134 @@
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';
import { createUser } from '../../../../../test/factories/user';
import { createConnection } from '../../../../../test/factories/connection';
import { createFlow } from '../../../../../test/factories/flow';
import { createStep } from '../../../../../test/factories/step';
import { createPermission } from '../../../../../test/factories/permission';
describe('DELETE /api/v1/steps/:stepId', () => {
let currentUser, currentUserRole, token;
beforeEach(async () => {
currentUser = await createUser();
currentUserRole = await currentUser.$relatedQuery('role');
token = await createAuthTokenByUserId(currentUser.id);
});
it('should remove the step of the current user and return no content', async () => {
const currentUserFlow = await createFlow({ userId: currentUser.id });
const currentUserConnection = await createConnection();
await createStep({
flowId: currentUserFlow.id,
connectionId: currentUserConnection.id,
});
const actionStep = await createStep({
flowId: currentUserFlow.id,
connectionId: currentUserConnection.id,
});
await createPermission({
action: 'read',
subject: 'Flow',
roleId: currentUserRole.id,
conditions: ['isCreator'],
});
await createPermission({
action: 'update',
subject: 'Flow',
roleId: currentUserRole.id,
conditions: ['isCreator'],
});
await request(app)
.delete(`/api/v1/steps/${actionStep.id}`)
.set('Authorization', token)
.expect(204);
});
it('should remove the step of the another user and return no content', async () => {
const anotherUser = await createUser();
const anotherUserFlow = await createFlow({ userId: anotherUser.id });
const anotherUserConnection = await createConnection();
await createStep({
flowId: anotherUserFlow.id,
connectionId: anotherUserConnection.id,
});
const actionStep = await createStep({
flowId: anotherUserFlow.id,
connectionId: anotherUserConnection.id,
});
await createPermission({
action: 'read',
subject: 'Flow',
roleId: currentUserRole.id,
conditions: [],
});
await createPermission({
action: 'update',
subject: 'Flow',
roleId: currentUserRole.id,
conditions: [],
});
await request(app)
.delete(`/api/v1/steps/${actionStep.id}`)
.set('Authorization', token)
.expect(204);
});
it('should return not found response for not existing step UUID', async () => {
await createPermission({
action: 'update',
subject: 'Flow',
roleId: currentUserRole.id,
conditions: [],
});
await createPermission({
action: 'read',
subject: 'Flow',
roleId: currentUserRole.id,
conditions: [],
});
const notExistingStepUUID = Crypto.randomUUID();
await request(app)
.delete(`/api/v1/steps/${notExistingStepUUID}`)
.set('Authorization', token)
.expect(404);
});
it('should return bad request response for invalid step UUID', async () => {
await createPermission({
action: 'update',
subject: 'Flow',
roleId: currentUserRole.id,
conditions: [],
});
await createPermission({
action: 'read',
subject: 'Flow',
roleId: currentUserRole.id,
conditions: [],
});
await request(app)
.delete('/api/v1/steps/invalidStepUUID')
.set('Authorization', token)
.expect(400);
});
});

View File

@@ -63,6 +63,10 @@ const authorizationList = {
action: 'read',
subject: 'Execution',
},
'DELETE /api/v1/steps/:stepId': {
action: 'update',
subject: 'Flow',
},
};
export const authorizeUser = async (request, response, next) => {

View File

@@ -207,7 +207,9 @@ class Step extends Base {
const additionalFields = setupField.additionalFields;
if (additionalFields) {
const keyArgument = additionalFields.arguments.find(argument => argument.name === 'key');
const keyArgument = additionalFields.arguments.find(
(argument) => argument.name === 'key'
);
const dynamicFieldsKey = keyArgument.value;
const dynamicFields = await this.createDynamicFields(
@@ -289,6 +291,25 @@ class Step extends Base {
return this;
}
async delete() {
await this.$relatedQuery('executionSteps').delete();
await this.$query().delete();
const flow = await this.$relatedQuery('flow');
const nextSteps = await flow
.$relatedQuery('steps')
.where('position', '>', this.position);
const nextStepQueries = nextSteps.map(async (nextStep) => {
await nextStep.$query().patch({
position: nextStep.position - 1,
});
});
await Promise.all(nextStepQueries);
}
}
export default Step;

View File

@@ -6,6 +6,7 @@ import getConnectionAction from '../../../controllers/api/v1/steps/get-connectio
import getPreviousStepsAction from '../../../controllers/api/v1/steps/get-previous-steps.js';
import createDynamicFieldsAction from '../../../controllers/api/v1/steps/create-dynamic-fields.js';
import createDynamicDataAction from '../../../controllers/api/v1/steps/create-dynamic-data.js';
import deleteStepAction from '../../../controllers/api/v1/steps/delete-step.js';
const router = Router();
@@ -37,4 +38,11 @@ router.post(
asyncHandler(createDynamicDataAction)
);
router.delete(
'/:stepId',
authenticateUser,
authorizeUser,
asyncHandler(deleteStepAction)
);
export default router;