diff --git a/packages/nocodb/.gitignore b/packages/nocodb/.gitignore index 5dee866dfe..3fbe40644f 100644 --- a/packages/nocodb/.gitignore +++ b/packages/nocodb/.gitignore @@ -18,6 +18,4 @@ noco.db* /docker/main.js test_meta.db test_sakila.db -test_noco.db-shm -test_noco.db-wal .env \ No newline at end of file diff --git a/packages/nocodb/src/lib/Noco.ts b/packages/nocodb/src/lib/Noco.ts index 81f6faf362..e9a7f0e57b 100644 --- a/packages/nocodb/src/lib/Noco.ts +++ b/packages/nocodb/src/lib/Noco.ts @@ -43,7 +43,6 @@ import * as http from 'http'; import weAreHiring from './utils/weAreHiring'; import getInstance from './utils/getInstance'; import initAdminFromEnv from './meta/api/userApi/initAdminFromEnv'; -import UserCreatorService from './services/user/UserCreatorService'; const log = debug('nc:app'); require('dotenv').config(); @@ -277,20 +276,6 @@ export default class Noco { }); Tele.emit('evt_app_started', await User.count()); weAreHiring(); - - if (process.env.TEST === 'true') { - if (!(await User.getByEmail('user@nocodb.com'))) { - const service = new UserCreatorService({ - email: 'user@nocodb.com', - password: 'Password123.', - ignoreSubscribe: true, - clientInfo: {} as any, - nocoConfig: this.config, - }); - await service.process(); - } - } - return this.router; } diff --git a/packages/nocodb/src/lib/db/sql-client/lib/sqlite/SqliteClient.ts b/packages/nocodb/src/lib/db/sql-client/lib/sqlite/SqliteClient.ts index d1e4c4d863..394b65650f 100644 --- a/packages/nocodb/src/lib/db/sql-client/lib/sqlite/SqliteClient.ts +++ b/packages/nocodb/src/lib/db/sql-client/lib/sqlite/SqliteClient.ts @@ -1443,107 +1443,6 @@ class SqliteClient extends KnexClient { return result; } - private async _tableUpdate(args) { - const result = new Result(); - - args.table = args.tn; - const originalColumns = args.originalColumns; - args.connectionConfig = this._connectionConfig; - args.sqlClient = this.sqlClient; - - let upQuery = ''; - let downQuery = ''; - - for (let i = 0; i < args.columns.length; ++i) { - const oldColumn = lodash.find(originalColumns, { - cn: args.columns[i].cno, - }); - - if (args.columns[i].altered & 4) { - // col remove - upQuery += await this.alterTableRemoveColumn( - args.table, - args.columns[i], - oldColumn, - upQuery - ); - downQuery += this.alterTableAddColumn( - args.table, - oldColumn, - args.columns[i], - downQuery - ); - } else if (args.columns[i].altered & 2 || args.columns[i].altered & 8) { - // col edit - upQuery += this.alterTableChangeColumn( - args.table, - args.columns[i], - oldColumn, - upQuery - ); - downQuery += ';'; - // downQuery += this.alterTableChangeColumn( - // args.table, - // oldColumn, - // args.columns[i], - // downQuery, - // this.sqlClient - // ); - } else if (args.columns[i].altered & 1) { - // col addition - upQuery += this.alterTableAddColumn( - args.table, - args.columns[i], - oldColumn, - upQuery - ); - downQuery += ';'; - // downQuery += alterTableRemoveColumn( - // args.table, - // args.columns[i], - // oldColumn, - // downQuery, - // this.sqlClient - // ); - } - } - - upQuery += this.alterTablePK( - args.columns, - args.originalColumns, - upQuery, - this.sqlClient - ); - //downQuery += alterTablePK(args.originalColumns, args.columns, downQuery); - - if (upQuery) { - //upQuery = `ALTER TABLE ${args.columns[0].tn} ${upQuery};`; - //downQuery = `ALTER TABLE ${args.columns[0].tn} ${downQuery};`; - } - - await Promise.all( - upQuery.split(';').map(async (query) => { - if (query.trim().length) await this.sqlClient.raw(query); - }) - ); - - // await this.sqlClient.raw(upQuery); - - console.log(upQuery); - - const afterUpdate = await this.afterTableUpdate(args); - - result.data.object = { - upStatement: [ - { sql: this.querySeparator() + upQuery }, - ...afterUpdate.upStatement, - ], - downStatement: [{ sql: ';' }], - }; - - return result; - } - /** * * @param {Object} - args @@ -1573,24 +1472,109 @@ class SqliteClient extends KnexClient { */ async tableUpdate(args) { const _func = this.tableUpdate.name; + const result = new Result(); log.api(`${_func}:args:`, args); - // for (let retry = 0; retry < 3; retry++) { - // try { - // return await this._tableUpdate(args); - // } catch (e) { - // console.log('retrying:tableUpdate', e); - // } - // // Wait for 300ms - // await new Promise((resolve) => setTimeout(resolve, 300)); - // } - try { - return await this._tableUpdate(args); + args.table = args.tn; + const originalColumns = args.originalColumns; + args.connectionConfig = this._connectionConfig; + args.sqlClient = this.sqlClient; + + let upQuery = ''; + let downQuery = ''; + + for (let i = 0; i < args.columns.length; ++i) { + const oldColumn = lodash.find(originalColumns, { + cn: args.columns[i].cno, + }); + + if (args.columns[i].altered & 4) { + // col remove + upQuery += await this.alterTableRemoveColumn( + args.table, + args.columns[i], + oldColumn, + upQuery + ); + downQuery += this.alterTableAddColumn( + args.table, + oldColumn, + args.columns[i], + downQuery + ); + } else if (args.columns[i].altered & 2 || args.columns[i].altered & 8) { + // col edit + upQuery += this.alterTableChangeColumn( + args.table, + args.columns[i], + oldColumn, + upQuery + ); + downQuery += ';'; + // downQuery += this.alterTableChangeColumn( + // args.table, + // oldColumn, + // args.columns[i], + // downQuery, + // this.sqlClient + // ); + } else if (args.columns[i].altered & 1) { + // col addition + upQuery += this.alterTableAddColumn( + args.table, + args.columns[i], + oldColumn, + upQuery + ); + downQuery += ';'; + // downQuery += alterTableRemoveColumn( + // args.table, + // args.columns[i], + // oldColumn, + // downQuery, + // this.sqlClient + // ); + } + } + + upQuery += this.alterTablePK( + args.columns, + args.originalColumns, + upQuery, + this.sqlClient + ); + //downQuery += alterTablePK(args.originalColumns, args.columns, downQuery); + + if (upQuery) { + //upQuery = `ALTER TABLE ${args.columns[0].tn} ${upQuery};`; + //downQuery = `ALTER TABLE ${args.columns[0].tn} ${downQuery};`; + } + + await Promise.all( + upQuery.split(';').map(async (query) => { + if (query.trim().length) await this.sqlClient.raw(query); + }) + ); + + // await this.sqlClient.raw(upQuery); + + console.log(upQuery); + + const afterUpdate = await this.afterTableUpdate(args); + + result.data.object = { + upStatement: [ + { sql: this.querySeparator() + upQuery }, + ...afterUpdate.upStatement, + ], + downStatement: [{ sql: ';' }], + }; } catch (e) { log.ppe(e, _func); throw e; } + return result; } /** diff --git a/packages/nocodb/src/lib/services/user/UserCreatorService.ts b/packages/nocodb/src/lib/services/user/UserCreatorService.ts deleted file mode 100644 index 6c37406fba..0000000000 --- a/packages/nocodb/src/lib/services/user/UserCreatorService.ts +++ /dev/null @@ -1,182 +0,0 @@ -import { validatePassword } from 'nocodb-sdk'; -import { promisify } from 'util'; -import { NcError } from '../../meta/helpers/catchError'; -import User from '../../models/User'; -const { isEmail } = require('validator'); -import bcrypt from 'bcryptjs'; -const { v4: uuidv4 } = require('uuid'); -import { Tele } from 'nc-help'; -import { randomTokenString } from '../../meta/helpers/stringHelpers'; -import { genJwt } from '../../meta/api/userApi/helpers'; -import Audit from '../../models/Audit'; -import NcPluginMgrv2 from '../../meta/helpers/NcPluginMgrv2'; -import * as ejs from 'ejs'; -import { NcConfig } from '../../../interface/config'; - -export default class UserCreatorService { - private readonly email: string; - private readonly password: string; - private readonly firstName: string; - private readonly lastName: string; - private readonly token: string; - private readonly ignoreSubscribe: boolean; - private readonly clientInfo: any; - private readonly nocoConfig: NcConfig; - - constructor(args: { - email: string; - password: string; - firstName?: string; - lastName?: string; - token?: string; - ignoreSubscribe?: boolean; - clientInfo: any; - nocoConfig: NcConfig; - }) { - this.email = args.email; - this.password = args.password; - this.firstName = args.firstName; - this.lastName = args.lastName; - this.token = args.token; - this.ignoreSubscribe = args.ignoreSubscribe; - this.clientInfo = args.clientInfo; - this.nocoConfig = args.nocoConfig; - } - - async process() { - const { - email: _email, - password, - firstName, - lastName, - clientInfo, - ignoreSubscribe, - token, - nocoConfig, - } = this; - - // validate password and throw error if password is satisfying the conditions - const { valid, error } = validatePassword(password); - if (!valid) { - NcError.badRequest(`Password : ${error}`); - } - - if (!isEmail(_email)) { - NcError.badRequest(`Invalid email`); - } - - const email = _email.toLowerCase(); - - const user = await User.getByEmail(email); - - if (user) { - if (token) { - if (token !== user.invite_token) { - NcError.badRequest(`Invalid invite url`); - } else if (user.invite_token_expires < new Date()) { - NcError.badRequest( - 'Expired invite url, Please contact super admin to get a new invite url' - ); - } - } else { - // todo : opening up signup for timebeing - // return next(new Error(`Email '${email}' already registered`)); - } - } - - const salt = await promisify(bcrypt.genSalt)(10); - const passwordHash = await promisify(bcrypt.hash)(password, salt); - const email_verification_token = uuidv4(); - - if (!ignoreSubscribe) { - Tele.emit('evt_subscribe', email); - } - - if (user) { - if (token) { - await User.update(user.id, { - firstname: firstName, - lastname: lastName, - salt, - password: passwordHash, - email_verification_token, - invite_token: null, - invite_token_expires: null, - email: user.email, - }); - } else { - NcError.badRequest('User already exist'); - } - } else { - let roles = 'user'; - - if (await User.isFirst()) { - roles = 'user,super'; - // todo: update in nc_store - // roles = 'owner,creator,editor' - Tele.emit('evt', { - evt_type: 'project:invite', - count: 1, - }); - } else { - if (process.env.NC_INVITE_ONLY_SIGNUP) { - NcError.badRequest('Not allowed to signup, contact super admin.'); - } else { - roles = 'user_new'; - } - } - - const token_version = randomTokenString(); - - await User.insert({ - firstname: firstName, - lastname: lastName, - email, - salt, - password: passwordHash, - email_verification_token, - roles, - token_version, - }); - } - const createdUser = await User.getByEmail(email); - - try { - const template = (await import('./ui/emailTemplates/verify')).default; - await ( - await NcPluginMgrv2.emailAdapter() - ).mailSend({ - to: email, - subject: 'Verify email', - html: ejs.render(template, { - verifyLink: - createdUser.ncSiteUrl + - `/email/verify/${createdUser.email_verification_token}`, - }), - }); - } catch (e) { - console.log( - 'Warning : `mailSend` failed, Please configure emailClient configuration.' - ); - } - - const refreshToken = randomTokenString(); - await User.update(createdUser.id, { - refresh_token: refreshToken, - email: createdUser.email, - }); - - await Audit.insert({ - op_type: 'AUTHENTICATION', - op_sub_type: 'SIGNUP', - user: createdUser.email, - description: `signed up `, - ip: clientInfo.clientIp, - }); - - return { - token: genJwt(createdUser, nocoConfig), - refreshToken, - }; - } -} diff --git a/packages/nocodb/src/lib/services/user/ui/auth/emailVerify.ts b/packages/nocodb/src/lib/services/user/ui/auth/emailVerify.ts deleted file mode 100644 index 17275b3d36..0000000000 --- a/packages/nocodb/src/lib/services/user/ui/auth/emailVerify.ts +++ /dev/null @@ -1,94 +0,0 @@ -export default ` - - - NocoDB - Verify Email - - - - - - - - -
- - - - - - Email verified successfully! - - - {{errMsg}} - - - - - - - -
- - - - - -`; -/** - * @copyright Copyright (c) 2021, Xgene Cloud Ltd - * - * @author Naveen MR - * @author Pranav C Balan - * @author Wing-Kam Wong - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ diff --git a/packages/nocodb/src/lib/services/user/ui/auth/resetPassword.ts b/packages/nocodb/src/lib/services/user/ui/auth/resetPassword.ts deleted file mode 100644 index 36ce73b3e3..0000000000 --- a/packages/nocodb/src/lib/services/user/ui/auth/resetPassword.ts +++ /dev/null @@ -1,128 +0,0 @@ -export default ` - - - NocoDB - Reset Password - - - - - - - - -
- - - - - - Password reset successful! - - - - - - -
- - - - - -`; -/** - * @copyright Copyright (c) 2021, Xgene Cloud Ltd - * - * @author Naveen MR - * @author Pranav C Balan - * @author Wing-Kam Wong - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ diff --git a/packages/nocodb/src/lib/services/user/ui/emailTemplates/forgotPassword.ts b/packages/nocodb/src/lib/services/user/ui/emailTemplates/forgotPassword.ts deleted file mode 100644 index ad431383fd..0000000000 --- a/packages/nocodb/src/lib/services/user/ui/emailTemplates/forgotPassword.ts +++ /dev/null @@ -1,193 +0,0 @@ -export default ` - - - - - Simple Transactional Email - - - - - - - - - - - - - -`; -/** - * @copyright Copyright (c) 2021, Xgene Cloud Ltd - * - * @author Naveen MR - * @author Pranav C Balan - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ diff --git a/packages/nocodb/src/lib/services/user/ui/emailTemplates/invite.ts b/packages/nocodb/src/lib/services/user/ui/emailTemplates/invite.ts deleted file mode 100644 index 8e143bd938..0000000000 --- a/packages/nocodb/src/lib/services/user/ui/emailTemplates/invite.ts +++ /dev/null @@ -1,231 +0,0 @@ -export default ` - - - - - Simple Transactional Email - - - - - - - - - - - - - -`; - -/** - * @copyright Copyright (c) 2021, Xgene Cloud Ltd - * - * @author Naveen MR - * @author Pranav C Balan - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ diff --git a/packages/nocodb/src/lib/services/user/ui/emailTemplates/verify.ts b/packages/nocodb/src/lib/services/user/ui/emailTemplates/verify.ts deleted file mode 100644 index 6b5e76ab54..0000000000 --- a/packages/nocodb/src/lib/services/user/ui/emailTemplates/verify.ts +++ /dev/null @@ -1,230 +0,0 @@ -export default ` - - - - - Simple Transactional Email - - - - - - - - - - - - - -`; - -/** - * @copyright Copyright (c) 2021, Xgene Cloud Ltd - * - * @author Naveen MR - * @author Pranav C Balan - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ diff --git a/packages/nocodb/src/lib/utils/NcConfigFactory.ts b/packages/nocodb/src/lib/utils/NcConfigFactory.ts index b157762fac..75c7924475 100644 --- a/packages/nocodb/src/lib/utils/NcConfigFactory.ts +++ b/packages/nocodb/src/lib/utils/NcConfigFactory.ts @@ -590,10 +590,6 @@ export default class NcConfigFactory implements NcConfig { ...args.meta.db, connection: args.meta.db, }); - if (process.env['TEST'] === 'true') { - await metaSqlClient.raw('PRAGMA journal_mode=WAL'); - await metaSqlClient.raw('PRAGMA busy_timeout=60000'); - } await metaSqlClient.createDatabaseIfNotExists({ database: args.meta.db?.connection?.filename, }); @@ -630,7 +626,7 @@ export default class NcConfigFactory implements NcConfig { db: { client: 'sqlite3', connection: { - filename: process.env['TEST'] !== 'true' ? 'noco.db' : 'test_noco.db', + filename: 'noco.db', }, }, }; diff --git a/packages/nocodb/src/run/testDocker.ts b/packages/nocodb/src/run/testDocker.ts new file mode 100644 index 0000000000..729b9c6922 --- /dev/null +++ b/packages/nocodb/src/run/testDocker.ts @@ -0,0 +1,65 @@ +import axios from 'axios'; +import cors from 'cors'; +import express from 'express'; + +import Noco from '../lib/Noco'; +import User from '../lib/models/User'; +process.env.NC_VERSION = '0009044'; + +const server = express(); +server.enable('trust proxy'); +server.disable('etag'); +server.disable('x-powered-by'); +server.use( + cors({ + exposedHeaders: 'xc-db-response', + }) +); + +server.set('view engine', 'ejs'); + +process.env[`DEBUG`] = 'xc*'; + +(async () => { + const httpServer = server.listen(process.env.PORT || 8080, () => { + console.log(`App started successfully.\nVisit -> ${Noco.dashboardUrl}`); + }); + server.use(await Noco.init({}, httpServer, server)); + + // Wait for 0.5 seconds for the server to start + await new Promise((resolve) => setTimeout(resolve, 500)); + + if (!(await User.getByEmail('user@nocodb.com'))) { + const response = await axios.post( + `http://localhost:${process.env.PORT || 8080}/api/v1/auth/user/signup`, + { + email: 'user@nocodb.com', + password: 'Password123.', + } + ); + console.log(response.data); + } +})().catch((e) => console.log(e)); + +/** + * @copyright Copyright (c) 2021, Xgene Cloud Ltd + * + * @author Naveen MR + * @author Pranav C Balan + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ diff --git a/scripts/playwright/pages/Dashboard/Grid/index.ts b/scripts/playwright/pages/Dashboard/Grid/index.ts index 37b0af7b0c..9fdfb89bd7 100644 --- a/scripts/playwright/pages/Dashboard/Grid/index.ts +++ b/scripts/playwright/pages/Dashboard/Grid/index.ts @@ -66,7 +66,7 @@ export class GridPage extends BasePage { const rowCount = await this.get().locator(".nc-grid-row").count(); await this.get().locator(".nc-grid-add-new-cell").click(); - expect + await expect .poll(async () => await this.get().locator(".nc-grid-row").count()) .toBe(rowCount + 1); diff --git a/scripts/playwright/tests/linkToAnotherRecord.spec.ts b/scripts/playwright/tests/linkToAnotherRecord.spec.ts index 1cfbbec264..a67525ea2c 100644 --- a/scripts/playwright/tests/linkToAnotherRecord.spec.ts +++ b/scripts/playwright/tests/linkToAnotherRecord.spec.ts @@ -2,7 +2,7 @@ import { test } from "@playwright/test"; import { DashboardPage } from "../pages/Dashboard"; import setup from "../setup"; -test.describe("LTAR create & update", () => { +test.describe.only("LTAR create & update", () => { let dashboard: DashboardPage; let context: any;