From befca3f30b40702d11ffb4e03a73d7df634e7c06 Mon Sep 17 00:00:00 2001 From: Faruk AYDIN Date: Tue, 6 May 2025 17:04:05 +0200 Subject: [PATCH 1/2] feat: Convert folders API endpoints to user-scoped ones --- .../api/v1/folders/delete-folder.ee.js | 11 ----- .../api/v1/folders/get-folders.ee.js | 8 ---- .../api/v1/folders/get-folders.ee.test.js | 47 ------------------- .../api/v1/users/delete-folder.ee.js | 16 +++++++ .../delete-folder.ee.test.js | 26 ++++++---- .../api/v1/users/get-folders.ee.test.js | 2 +- packages/backend/src/routes/api/index.js | 2 - .../backend/src/routes/api/v1/folders.ee.js | 10 ---- .../backend/src/routes/api/v1/users.ee.js | 2 + .../api/v1/{folders => users}/get-folders.js | 0 10 files changed, 37 insertions(+), 87 deletions(-) delete mode 100644 packages/backend/src/controllers/api/v1/folders/delete-folder.ee.js delete mode 100644 packages/backend/src/controllers/api/v1/folders/get-folders.ee.js delete mode 100644 packages/backend/src/controllers/api/v1/folders/get-folders.ee.test.js create mode 100644 packages/backend/src/controllers/api/v1/users/delete-folder.ee.js rename packages/backend/src/controllers/api/v1/{folders => users}/delete-folder.ee.test.js (54%) delete mode 100644 packages/backend/src/routes/api/v1/folders.ee.js rename packages/backend/test/mocks/rest/api/v1/{folders => users}/get-folders.js (100%) diff --git a/packages/backend/src/controllers/api/v1/folders/delete-folder.ee.js b/packages/backend/src/controllers/api/v1/folders/delete-folder.ee.js deleted file mode 100644 index 47b58a36..00000000 --- a/packages/backend/src/controllers/api/v1/folders/delete-folder.ee.js +++ /dev/null @@ -1,11 +0,0 @@ -import Folder from '../../../../models/folder.js'; - -export default async (request, response) => { - const folder = await Folder.query() - .findById(request.params.folderId) - .throwIfNotFound(); - - await folder.delete(); - - response.status(204).end(); -}; diff --git a/packages/backend/src/controllers/api/v1/folders/get-folders.ee.js b/packages/backend/src/controllers/api/v1/folders/get-folders.ee.js deleted file mode 100644 index dda1da5d..00000000 --- a/packages/backend/src/controllers/api/v1/folders/get-folders.ee.js +++ /dev/null @@ -1,8 +0,0 @@ -import { renderObject } from '../../../../helpers/renderer.js'; -import Folder from '../../../../models/folder.js'; - -export default async (request, response) => { - const folders = await Folder.query().orderBy('name', 'asc'); - - renderObject(response, folders); -}; diff --git a/packages/backend/src/controllers/api/v1/folders/get-folders.ee.test.js b/packages/backend/src/controllers/api/v1/folders/get-folders.ee.test.js deleted file mode 100644 index 2dbbcd6f..00000000 --- a/packages/backend/src/controllers/api/v1/folders/get-folders.ee.test.js +++ /dev/null @@ -1,47 +0,0 @@ -import { vi, describe, it, expect, beforeEach } from 'vitest'; -import request from 'supertest'; -import app from '../../../../app.js'; -import { createApiToken } from '../../../../../test/factories/api-token.js'; -import { createUser } from '../../../../../test/factories/user.js'; -import { createFolder } from '../../../../../test/factories/folder.js'; -import getFoldersMock from '../../../../../test/mocks/rest/api/v1/folders/get-folders.js'; -import * as license from '../../../../helpers/license.ee.js'; - -describe('GET /api/v1/folders', () => { - let folderA, folderB, folderC, currentUser, anotherUser, token; - - beforeEach(async () => { - vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true); - - currentUser = await createUser(); - anotherUser = await createUser(); - - folderC = await createFolder({ - name: 'Folder C', - userId: currentUser.id, - }); - - folderA = await createFolder({ - name: 'Folder A', - userId: anotherUser.id, - }); - - folderB = await createFolder({ - name: 'Folder B', - userId: anotherUser.id, - }); - - token = (await createApiToken()).token; - }); - - it('should return all folders', async () => { - const response = await request(app) - .get('/api/v1/folders') - .set('x-api-token', token) - .expect(200); - - const expectedPayload = await getFoldersMock([folderA, folderB, folderC]); - - expect(response.body).toStrictEqual(expectedPayload); - }); -}); diff --git a/packages/backend/src/controllers/api/v1/users/delete-folder.ee.js b/packages/backend/src/controllers/api/v1/users/delete-folder.ee.js new file mode 100644 index 00000000..bbbe1e6c --- /dev/null +++ b/packages/backend/src/controllers/api/v1/users/delete-folder.ee.js @@ -0,0 +1,16 @@ +import User from '../../../../models/user.js'; + +export default async (request, response) => { + const user = await User.query() + .findById(request.params.userId) + .throwIfNotFound(); + + const folder = await user + .$relatedQuery('folders') + .findById(request.params.folderId) + .throwIfNotFound(); + + await folder.delete(); + + response.status(204).end(); +}; diff --git a/packages/backend/src/controllers/api/v1/folders/delete-folder.ee.test.js b/packages/backend/src/controllers/api/v1/users/delete-folder.ee.test.js similarity index 54% rename from packages/backend/src/controllers/api/v1/folders/delete-folder.ee.test.js rename to packages/backend/src/controllers/api/v1/users/delete-folder.ee.test.js index c7d0aef0..4754e552 100644 --- a/packages/backend/src/controllers/api/v1/folders/delete-folder.ee.test.js +++ b/packages/backend/src/controllers/api/v1/users/delete-folder.ee.test.js @@ -3,39 +3,49 @@ import request from 'supertest'; import { beforeEach, describe, it, vi } from 'vitest'; import { createApiToken } from '../../../../../test/factories/api-token.js'; import { createFolder } from '../../../../../test/factories/folder.js'; +import { createUser } from '../../../../../test/factories/user.js'; import app from '../../../../app.js'; import * as license from '../../../../helpers/license.ee.js'; -describe('DELETE /api/v1/folders/:folderId', () => { - let token; +describe('DELETE /api/v1/users/:userId/folders/:folderId', () => { + let token, user, folder; beforeEach(async () => { vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true); token = (await createApiToken()).token; + user = await createUser(); + folder = await createFolder({ userId: user.id }); }); it('should remove the folder and return no content', async () => { - const folder = await createFolder(); - await request(app) - .delete(`/api/v1/folders/${folder.id}`) + .delete(`/api/v1/users/${folder.userId}/folders/${folder.id}`) .set('x-api-token', token) .expect(204); }); + it('should return not found response for not existing user UUID', async () => { + const notExistingUserUUID = Crypto.randomUUID(); + + await request(app) + .delete(`/api/v1/users/${notExistingUserUUID}/folders/${folder.id}`) + .set('x-api-token', token) + .expect(404); + }); + it('should return not found response for not existing folder UUID', async () => { const notExistingFolderUUID = Crypto.randomUUID(); await request(app) - .delete(`/api/v1/folders/${notExistingFolderUUID}`) + .delete(`/api/v1/users/${user.id}/folders/${notExistingFolderUUID}`) .set('x-api-token', token) .expect(404); }); - it('should return bad request response for invalid UUID', async () => { + it('should return bad request response for invalid folder UUID', async () => { await request(app) - .delete('/api/v1/folders/invalidFolderUUID') + .delete(`/api/v1/users/${user.id}/folders/invalidFolderUUID`) .set('x-api-token', token) .expect(400); }); diff --git a/packages/backend/src/controllers/api/v1/users/get-folders.ee.test.js b/packages/backend/src/controllers/api/v1/users/get-folders.ee.test.js index 2e418c98..e88c3830 100644 --- a/packages/backend/src/controllers/api/v1/users/get-folders.ee.test.js +++ b/packages/backend/src/controllers/api/v1/users/get-folders.ee.test.js @@ -5,7 +5,7 @@ import app from '../../../../app.js'; import { createApiToken } from '../../../../../test/factories/api-token.js'; import { createUser } from '../../../../../test/factories/user.js'; import { createFolder } from '../../../../../test/factories/folder.js'; -import getFoldersMock from '../../../../../test/mocks/rest/api/v1/folders/get-folders.js'; +import getFoldersMock from '../../../../../test/mocks/rest/api/v1/users/get-folders.js'; import * as license from '../../../../helpers/license.ee.js'; describe('GET /api/v1/users/:userId/folders', () => { diff --git a/packages/backend/src/routes/api/index.js b/packages/backend/src/routes/api/index.js index 65afba12..c20af0cc 100644 --- a/packages/backend/src/routes/api/index.js +++ b/packages/backend/src/routes/api/index.js @@ -2,7 +2,6 @@ import { Router } from 'express'; import appsRouter from './v1/apps.ee.js'; import executionsRouter from './v1/executions.ee.js'; import flowsRouter from './v1/flows.ee.js'; -import foldersRouter from './v1/folders.ee.js'; import templatesRouter from './v1/templates.ee.js'; import usersRouter from './v1/users.ee.js'; import userInvitationsRouter from './v1/user-invitations.ee.js'; @@ -12,7 +11,6 @@ const router = Router(); router.use('/v1/apps', appsRouter); router.use('/v1/executions', executionsRouter); router.use('/v1/flows', flowsRouter); -router.use('/v1/folders', foldersRouter); router.use('/v1/templates', templatesRouter); router.use('/v1/users', usersRouter); router.use('/v1/user-invitations', userInvitationsRouter); diff --git a/packages/backend/src/routes/api/v1/folders.ee.js b/packages/backend/src/routes/api/v1/folders.ee.js deleted file mode 100644 index 250098db..00000000 --- a/packages/backend/src/routes/api/v1/folders.ee.js +++ /dev/null @@ -1,10 +0,0 @@ -import { Router } from 'express'; -import getFoldersAction from '../../../controllers/api/v1/folders/get-folders.ee.js'; -import deleteFolderAction from '../../../controllers/api/v1/folders/delete-folder.ee.js'; - -const router = Router(); - -router.get('/', getFoldersAction); -router.delete('/:folderId', deleteFolderAction); - -export default router; diff --git a/packages/backend/src/routes/api/v1/users.ee.js b/packages/backend/src/routes/api/v1/users.ee.js index e49e6d96..286cd7c4 100644 --- a/packages/backend/src/routes/api/v1/users.ee.js +++ b/packages/backend/src/routes/api/v1/users.ee.js @@ -4,6 +4,7 @@ import getFoldersAction from '../../../controllers/api/v1/users/get-folders.ee.j import getUserAction from '../../../controllers/api/v1/users/get-user.ee.js'; import deleteUserAction from '../../../controllers/api/v1/users/delete-user.ee.js'; import getUsersAction from '../../../controllers/api/v1/users/get-users.ee.js'; +import deleteFolderAction from '../../../controllers/api/v1/users/delete-folder.ee.js'; const router = Router(); @@ -12,5 +13,6 @@ router.get('/:userId', getUserAction); router.delete('/:userId', deleteUserAction); router.get('/:userId/folders', getFoldersAction); router.post('/:userId/folders', createFolderAction); +router.delete('/:userId/folders/:folderId', deleteFolderAction); export default router; diff --git a/packages/backend/test/mocks/rest/api/v1/folders/get-folders.js b/packages/backend/test/mocks/rest/api/v1/users/get-folders.js similarity index 100% rename from packages/backend/test/mocks/rest/api/v1/folders/get-folders.js rename to packages/backend/test/mocks/rest/api/v1/users/get-folders.js From bdc4acec03d4333d8280024d1ceb2036eead4075 Mon Sep 17 00:00:00 2001 From: Faruk AYDIN Date: Wed, 7 May 2025 10:21:49 +0200 Subject: [PATCH 2/2] chore: Manually update the test coverage --- packages/backend/vitest.config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/backend/vitest.config.js b/packages/backend/vitest.config.js index 911f8e03..2b24eddd 100644 --- a/packages/backend/vitest.config.js +++ b/packages/backend/vitest.config.js @@ -30,9 +30,9 @@ export default defineConfig({ autoUpdate: true, statements: 99.44, branches: 98.41, - functions: 99.1, + functions: 99.09, lines: 99.44, }, }, }, -}); \ No newline at end of file +});