From 9c62b2d3173f84dbdafe7848bbccff52200fa3f4 Mon Sep 17 00:00:00 2001 From: Akshay Date: Tue, 27 Dec 2022 16:18:36 +0530 Subject: [PATCH] Feature: Make tooljetdb optional (#5062) * make tooljetdb optional * restrict routes when tooljetdb is disabled * validate dbname before creating database * fix comment * format --- .env.example | 1 + .github/workflows/render-preview-deploy.yml | 4 ++ deploy/docker/.env.example | 1 + .../version-2.0.0-beta/setup/env-vars.md | 8 +++ frontend/src/App/App.jsx | 16 +++--- frontend/src/_ui/Layout/index.jsx | 56 ++++++++++--------- frontend/webpack.config.js | 1 + render.yaml | 2 + .../1665507074072-CreateTooljetDb.ts | 29 ---------- server/scripts/create-database.ts | 30 +++++++--- server/scripts/drop-database.ts | 14 ++++- server/src/app.module.ts | 5 +- server/src/services/app_config.service.ts | 1 + 13 files changed, 93 insertions(+), 75 deletions(-) delete mode 100644 server/migrations/1665507074072-CreateTooljetDb.ts diff --git a/.env.example b/.env.example index 40fb101f00..0c2c664d72 100644 --- a/.env.example +++ b/.env.example @@ -66,3 +66,4 @@ SSO_DISABLE_SIGNUPS= #ONBOARDING ENABLE_ONBOARDING_QUESTIONS_FOR_ALL_SIGN_UPS= +ENABLE_TOOLJET_DB= diff --git a/.github/workflows/render-preview-deploy.yml b/.github/workflows/render-preview-deploy.yml index 30ebf0d6c6..17cda504ab 100644 --- a/.github/workflows/render-preview-deploy.yml +++ b/.github/workflows/render-preview-deploy.yml @@ -57,6 +57,10 @@ jobs: "key": "PG_DB", "value": "${{ env.PR_NUMBER }}" }, + { + "key": "ENABLE_TOOLJET_DB", + "value": "true" + }, { "key": "TOOLJET_DB", "value": "TJDB_${{ env.PR_NUMBER }}" diff --git a/deploy/docker/.env.example b/deploy/docker/.env.example index 0f5f84d5f3..011c5e3e7c 100644 --- a/deploy/docker/.env.example +++ b/deploy/docker/.env.example @@ -42,6 +42,7 @@ SENTRY_DEBUG= # FEATURE TOGGLE COMMENT_FEATURE_ENABLE= ENABLE_MULTIPLAYER_EDITING=true +ENABLE_TOOLJET_DB= #SSO SSO_DISABLE_SIGNUP= diff --git a/docs/versioned_docs/version-2.0.0-beta/setup/env-vars.md b/docs/versioned_docs/version-2.0.0-beta/setup/env-vars.md index da4656fa31..c879ae3d7b 100644 --- a/docs/versioned_docs/version-2.0.0-beta/setup/env-vars.md +++ b/docs/versioned_docs/version-2.0.0-beta/setup/env-vars.md @@ -77,6 +77,14 @@ Use this environment variable to enable/disable the feature that allows users to | -------- | ---------------------- | | ENABLE_MARKETPLACE_FEATURE | `true` or `false` | +#### ToolJet Database feature enable ( optional ) + +Use this environment variable to enable/disable the feature that allows users to work with inbuilt data store to build apps with. + +| variable | value | +| ----------------- | ----------------- | +| ENABLE_TOOLJET_DB | `true` or `false` | + #### Server Host ( optional ) You can specify a different server for backend if it is hosted on another server. diff --git a/frontend/src/App/App.jsx b/frontend/src/App/App.jsx index f74a9b6a26..7dfe3a80a5 100644 --- a/frontend/src/App/App.jsx +++ b/frontend/src/App/App.jsx @@ -228,13 +228,15 @@ class App extends React.Component { switchDarkMode={this.switchDarkMode} darkMode={darkMode} /> - + {window.public_config?.ENABLE_TOOLJET_DB == 'true' && ( + + )} {window.public_config?.ENABLE_MARKETPLACE_FEATURE && ( -
  • - - - - + + + - - - - -
  • + height="33" + viewBox="0 0 32 33" + fill="none" + xmlns="http://www.w3.org/2000/svg" + > + + + + + + + )}
  • diff --git a/frontend/webpack.config.js b/frontend/webpack.config.js index 5be16d07eb..c5d0f280b6 100644 --- a/frontend/webpack.config.js +++ b/frontend/webpack.config.js @@ -158,6 +158,7 @@ module.exports = { apiUrl: `${stripTrailingSlash(API_URL[environment]) || ''}/api`, SERVER_IP: process.env.SERVER_IP, COMMENT_FEATURE_ENABLE: process.env.COMMENT_FEATURE_ENABLE ?? true, + ENABLE_TOOLJET_DB: process.env.ENABLE_TOOLJET_DB ?? true, ENABLE_MULTIPLAYER_EDITING: true, TOOLJET_MARKETPLACE_URL: process.env.TOOLJET_MARKETPLACE_URL || 'https://tooljet-plugins-production.s3.us-east-2.amazonaws.com', diff --git a/render.yaml b/render.yaml index 8926770b8e..1296af09b1 100644 --- a/render.yaml +++ b/render.yaml @@ -15,6 +15,8 @@ services: property: connectionString - key: TOOLJET_DB value: 'tooljet_db' + - key: ENABLE_TOOLJET_DB + value: 'true' - key: TOOLJET_HOST fromService: type: web diff --git a/server/migrations/1665507074072-CreateTooljetDb.ts b/server/migrations/1665507074072-CreateTooljetDb.ts deleted file mode 100644 index 5a9707d538..0000000000 --- a/server/migrations/1665507074072-CreateTooljetDb.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { getManager, MigrationInterface, QueryRunner } from 'typeorm'; -import { getEnvVars } from '../scripts/database-config-utils'; - -// This migration is a prerequisite for tooljetDb and incase the PG_USER -// dont have createdb privileges, this migration needs to be run for -// internal storage to function -export class CreateTooljetDb1665507074072 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - const data = getEnvVars(); - if (data.PG_DB_OWNER !== 'false') { - // Database creation can't be made inside a transaction block which queryRunner is run inside. - // Thus we get a new connection to create the database first. - try { - await getManager().query(`CREATE DATABASE ${data.TOOLJET_DB} WITH OWNER ${data.PG_USER};`); - } catch (err) { - const errorMessage = `database "${data.TOOLJET_DB}" already exists`; - if (err.message.includes(errorMessage)) return; - throw err; - } - } - } - - public async down(_queryRunner: QueryRunner): Promise { - const data = getEnvVars(); - if (data.PG_DB_OWNER !== 'false') { - await getManager().query(`DROP DATABASE ${data.TOOLJET_DB}`); - } - } -} diff --git a/server/scripts/create-database.ts b/server/scripts/create-database.ts index 42e8702f80..68f02f9dc8 100644 --- a/server/scripts/create-database.ts +++ b/server/scripts/create-database.ts @@ -3,6 +3,7 @@ import * as dotenv from 'dotenv'; import * as fs from 'fs'; import { exec } from 'child_process'; import { buildAndValidateDatabaseConfig } from './database-config-utils'; +import { isEmpty } from 'lodash'; function createDatabaseFromFile(envPath: string): void { const result = dotenv.config({ path: envPath }); @@ -26,6 +27,11 @@ function createDatabase(): void { throw new Error(`Config validation error: ${error.message}`); } + if (envVars.PG_DB_OWNER === 'false') { + console.log('Skipping database creation'); + return; + } + const connectivityCheck = exec('command -v createdb'); connectivityCheck.on('exit', function (signal) { @@ -35,28 +41,37 @@ function createDatabase(): void { } }); - if (envVars.PG_DB_OWNER === 'false') { - console.log('Skipping database creation'); - return; + // Allow creating db based on cmd line arg + const dbNameFromArg = process.argv[2]; + if (dbNameFromArg) return createDb(envVars, dbNameFromArg); + + createDb(envVars, envVars.PG_DB); + if (process.env.ENABLE_TOOLJET_DB == 'true') { + createDb(envVars, envVars.TOOLJET_DB); } +} + +function createDb(envVars, dbName) { + if (isEmpty(dbName)) throw 'Database name cannot be empty'; const createdb = `PGPASSWORD="${envVars.PG_PASS}" createdb ` + `-h ${envVars.PG_HOST} ` + `-p ${envVars.PG_PORT} ` + `-U ${envVars.PG_USER} ` + - envVars.PG_DB; + dbName; exec(createdb, (err, _stdout, _stderr) => { if (!err) { - console.log(`Created database ${envVars.PG_DB}`); + console.log(`Created database ${dbName}`); return; } - const errorMessage = `database "${envVars.PG_DB}" already exists`; + const errorMessage = `database "${dbName}" already exists`; if (err.message.includes(errorMessage)) { - console.log(`Using database: ${envVars.PG_DB}`); + envVars.PG_DB == dbName && console.log(`Using PG_DB: ${dbName}`); + envVars.TOOLJET_DB == dbName && console.log(`Using TOOLJET_DB: ${dbName}`); } else { console.error(err); process.exit(1); @@ -74,6 +89,5 @@ if (fs.existsSync(nodeEnvPath)) { createDatabaseFromFile(fallbackPath); } else { console.log('Picking up config from the environment'); - createDatabase(); } diff --git a/server/scripts/drop-database.ts b/server/scripts/drop-database.ts index 33ab79c3ee..44732c091d 100644 --- a/server/scripts/drop-database.ts +++ b/server/scripts/drop-database.ts @@ -29,20 +29,28 @@ function dropDatabase(): void { } }); + // Allow dropping db based on cmd line arg + const dbNameFromArg = process.argv[2]; + if (dbNameFromArg) return dropDb(envVars, dbNameFromArg); + + dropDb(envVars, envVars.PG_DB); +} + +function dropDb(envVars, dbName) { const dropdb = `PGPASSWORD=${envVars.PG_PASS} dropdb ` + `-h ${envVars.PG_HOST} ` + `-p ${envVars.PG_PORT} ` + `-U ${envVars.PG_USER} ` + - envVars.PG_DB; + dbName; exec(dropdb, (err, _stdout, _stderr) => { if (!err) { - console.log(`Dropped database ${envVars.PG_DB}`); + console.log(`Dropped database ${dbName}`); return; } - const errorMessage = `database "${envVars.PG_DB}" does not exist`; + const errorMessage = `database "${dbName}" does not exist`; if (err.message.includes(errorMessage)) { console.log(errorMessage); diff --git a/server/src/app.module.ts b/server/src/app.module.ts index 364fa1de51..feffd3cea9 100644 --- a/server/src/app.module.ts +++ b/server/src/app.module.ts @@ -94,7 +94,6 @@ const imports = [ PluginsModule, EventsModule, AppEnvironmentsModule, - TooljetDbModule, ]; if (process.env.SERVE_CLIENT !== 'false') { @@ -145,6 +144,10 @@ if (process.env.COMMENT_FEATURE_ENABLE !== 'false') { imports.unshift(CommentModule, ThreadModule, CommentUsersModule); } +if (process.env.ENABLE_TOOLJET_DB === 'true') { + imports.unshift(TooljetDbModule); +} + @Module({ imports, controllers: [AppController], diff --git a/server/src/services/app_config.service.ts b/server/src/services/app_config.service.ts index a9b9b77c58..f8302d93dd 100644 --- a/server/src/services/app_config.service.ts +++ b/server/src/services/app_config.service.ts @@ -26,6 +26,7 @@ export class AppConfigService { 'SUB_PATH', 'DISABLE_MULTI_WORKSPACE', 'ENABLE_MARKETPLACE_FEATURE', + 'ENABLE_TOOLJET_DB', ]; }