From c80791267f2d3a8166b572a3b2414a866b45dbc1 Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Mon, 13 May 2024 14:00:12 +0000 Subject: [PATCH] refactor(installation): improve allow installation guard --- packages/backend/bin/database/utils.js | 3 +++ .../v1/installation/users/create-user.test.js | 24 ++++++++++++++++++- .../backend/src/helpers/allow-installation.js | 16 +++++++++++++ .../src/helpers/authorize-installation.js | 9 ------- .../src/routes/api/v1/installation/users.js | 4 ++-- 5 files changed, 44 insertions(+), 12 deletions(-) create mode 100644 packages/backend/src/helpers/allow-installation.js delete mode 100644 packages/backend/src/helpers/authorize-installation.js diff --git a/packages/backend/bin/database/utils.js b/packages/backend/bin/database/utils.js index 14124276..0a3ae129 100644 --- a/packages/backend/bin/database/utils.js +++ b/packages/backend/bin/database/utils.js @@ -2,6 +2,7 @@ import appConfig from '../../src/config/app.js'; import logger from '../../src/helpers/logger.js'; import client from './client.js'; import User from '../../src/models/user.js'; +import Config from '../../src/models/config.js'; import Role from '../../src/models/role.js'; import '../../src/config/orm.js'; import process from 'process'; @@ -45,6 +46,8 @@ export async function createUser( if (userCount === 0) { const user = await User.query().insertAndFetch(userParams); logger.info(`User has been saved: ${user.email}`); + + await Config.markInstallationCompleted(); } else { logger.info('No need to seed a user.'); } diff --git a/packages/backend/src/controllers/api/v1/installation/users/create-user.test.js b/packages/backend/src/controllers/api/v1/installation/users/create-user.test.js index 17de0174..a157dbb3 100644 --- a/packages/backend/src/controllers/api/v1/installation/users/create-user.test.js +++ b/packages/backend/src/controllers/api/v1/installation/users/create-user.test.js @@ -4,6 +4,7 @@ import app from '../../../../../app.js'; import Config from '../../../../../models/config.js'; import User from '../../../../../models/user.js'; import { createRole } from '../../../../../../test/factories/role'; +import { createUser } from '../../../../../../test/factories/user'; import { createInstallationCompletedConfig } from '../../../../../../test/factories/config'; describe('POST /api/v1/installation/users', () => { @@ -17,7 +18,7 @@ describe('POST /api/v1/installation/users', () => { }); describe('for incomplete installations', () => { - it('should respond with HTTP 204 with correct payload', async () => { + it('should respond with HTTP 204 with correct payload when no user', async () => { expect(await Config.isInstallationCompleted()).toBe(false); await request(app) @@ -34,6 +35,27 @@ describe('POST /api/v1/installation/users', () => { expect(user.roleId).toBe(adminRole.id); expect(await Config.isInstallationCompleted()).toBe(true); }); + + it('should respond with HTTP 403 with correct payload when one user exists at least', async () => { + expect(await Config.isInstallationCompleted()).toBe(false); + + await createUser(); + + const usersCountBefore = await User.query().resultSize(); + + await request(app) + .post('/api/v1/installation/users') + .send({ + email: 'user@automatisch.io', + password: 'password', + fullName: 'Initial admin' + }) + .expect(403); + + const usersCountAfter = await User.query().resultSize(); + + expect(usersCountBefore).toEqual(usersCountAfter); + }); }); describe('for completed installations', () => { diff --git a/packages/backend/src/helpers/allow-installation.js b/packages/backend/src/helpers/allow-installation.js new file mode 100644 index 00000000..33826a4b --- /dev/null +++ b/packages/backend/src/helpers/allow-installation.js @@ -0,0 +1,16 @@ +import Config from '../models/config.js'; +import User from '../models/user.js'; + +export async function allowInstallation(request, response, next) { + if (await Config.isInstallationCompleted()) { + return response.status(403).end(); + } + + const hasAnyUsers = await User.query().resultSize() > 0; + + if (hasAnyUsers) { + return response.status(403).end(); + } + + next(); +}; diff --git a/packages/backend/src/helpers/authorize-installation.js b/packages/backend/src/helpers/authorize-installation.js deleted file mode 100644 index 09a2b733..00000000 --- a/packages/backend/src/helpers/authorize-installation.js +++ /dev/null @@ -1,9 +0,0 @@ -import Config from '../models/config.js'; - -export async function authorizeInstallation(request, response, next) { - if (await Config.isInstallationCompleted()) { - return response.status(403).end(); - } else { - next(); - } -}; diff --git a/packages/backend/src/routes/api/v1/installation/users.js b/packages/backend/src/routes/api/v1/installation/users.js index f2b16feb..9a3c8fd7 100644 --- a/packages/backend/src/routes/api/v1/installation/users.js +++ b/packages/backend/src/routes/api/v1/installation/users.js @@ -1,13 +1,13 @@ import { Router } from 'express'; import asyncHandler from 'express-async-handler'; -import { authorizeInstallation } from '../../../../helpers/authorize-installation.js'; +import { allowInstallation } from '../../../../helpers/allow-installation.js'; import createUserAction from '../../../../controllers/api/v1/installation/users/create-user.js'; const router = Router(); router.post( '/', - authorizeInstallation, + allowInstallation, asyncHandler(createUserAction) );