Browse Source

Merge branch 'develop' into enhancement/hm-mm-cells

pull/5724/head
Wing-Kam Wong 2 years ago
parent
commit
8005ac0ae5
  1. 2
      packages/nc-gui/package-lock.json
  2. 2
      packages/nc-lib-gui/package.json
  3. 4
      packages/nocodb-sdk/package-lock.json
  4. 2
      packages/nocodb-sdk/package.json
  5. 4
      packages/nocodb/Dockerfile
  6. 4
      packages/nocodb/Dockerfile.local
  7. 20
      packages/nocodb/package-lock.json
  8. 4
      packages/nocodb/package.json
  9. 2
      packages/nocodb/src/Noco.ts
  10. 3
      packages/nocodb/src/app.module.ts
  11. 281
      packages/nocodb/src/helpers/initAdminFromEnv.ts
  12. 7
      packages/nocodb/src/middlewares/public/public.middleware.spec.ts
  13. 23
      packages/nocodb/src/middlewares/public/public.middleware.ts
  14. 0
      packages/nocodb/src/public/css/fonts.montserrat.css
  15. 0
      packages/nocodb/src/public/css/fonts.roboto.css
  16. 0
      packages/nocodb/src/public/css/materialdesignicons.5.x.min.css
  17. 0
      packages/nocodb/src/public/css/swagger-ui-bundle.4.5.2.min.css
  18. 0
      packages/nocodb/src/public/css/vuetify.2.x.min.css
  19. 0
      packages/nocodb/src/public/favicon.ico
  20. 0
      packages/nocodb/src/public/icon.png
  21. 0
      packages/nocodb/src/public/js/axios.0.19.2.min.js
  22. 0
      packages/nocodb/src/public/js/redoc.standalone.min.js
  23. 0
      packages/nocodb/src/public/js/swagger-ui-bundle.4.5.2.min.js
  24. 0
      packages/nocodb/src/public/js/vue.2.6.14.min.js
  25. 0
      packages/nocodb/src/public/js/vue.global.js
  26. 0
      packages/nocodb/src/public/js/vuetify.2.x.min.js
  27. 13
      packages/nocodb/src/services/app-init.service.ts
  28. 2
      packages/nocodb/webpack.config.js

2
packages/nc-gui/package-lock.json generated

@ -110,7 +110,7 @@
} }
}, },
"../nocodb-sdk": { "../nocodb-sdk": {
"version": "0.107.3", "version": "0.107.4",
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"dependencies": { "dependencies": {
"axios": "^0.21.1", "axios": "^0.21.1",

2
packages/nc-lib-gui/package.json

@ -1,6 +1,6 @@
{ {
"name": "nc-lib-gui", "name": "nc-lib-gui",
"version": "0.107.3", "version": "0.107.4",
"description": "NocoDB GUI", "description": "NocoDB GUI",
"author": { "author": {
"name": "NocoDB", "name": "NocoDB",

4
packages/nocodb-sdk/package-lock.json generated

@ -1,12 +1,12 @@
{ {
"name": "nocodb-sdk", "name": "nocodb-sdk",
"version": "0.107.3", "version": "0.107.4",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "nocodb-sdk", "name": "nocodb-sdk",
"version": "0.107.3", "version": "0.107.4",
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"dependencies": { "dependencies": {
"axios": "^0.21.1", "axios": "^0.21.1",

2
packages/nocodb-sdk/package.json

@ -1,6 +1,6 @@
{ {
"name": "nocodb-sdk", "name": "nocodb-sdk",
"version": "0.107.3", "version": "0.107.4",
"description": "NocoDB SDK", "description": "NocoDB SDK",
"main": "build/main/index.js", "main": "build/main/index.js",
"typings": "build/main/index.d.ts", "typings": "build/main/index.d.ts",

4
packages/nocodb/Dockerfile

@ -31,9 +31,7 @@ COPY ./package*.json ./
COPY ./docker/main.js ./docker/main.js COPY ./docker/main.js ./docker/main.js
#COPY ./docker/start.sh /usr/src/appEntry/start.sh #COPY ./docker/start.sh /usr/src/appEntry/start.sh
COPY ./docker/start-litestream.sh /usr/src/appEntry/start.sh COPY ./docker/start-litestream.sh /usr/src/appEntry/start.sh
COPY ./public/css/*.css ./docker/public/css/ COPY src/public/ ./docker/public/
COPY ./public/js/*.js ./docker/public/js/
COPY ./public/favicon.ico ./docker/public/
# install production dependencies, # install production dependencies,
# reduce node_module size with modclean & removing sqlite deps, # reduce node_module size with modclean & removing sqlite deps,

4
packages/nocodb/Dockerfile.local

@ -14,9 +14,7 @@ COPY ./package*.json ./
COPY ./docker/nc-gui/ ./docker/nc-gui/ COPY ./docker/nc-gui/ ./docker/nc-gui/
COPY ./docker/main.js ./docker/index.js COPY ./docker/main.js ./docker/index.js
COPY ./docker/start-local.sh /usr/src/appEntry/start.sh COPY ./docker/start-local.sh /usr/src/appEntry/start.sh
COPY ./public/css/*.css ./docker/public/css/ COPY src/public/ ./docker/public/
COPY ./public/js/*.js ./docker/public/js/
COPY ./public/favicon.ico ./docker/public/
# install production dependencies, # install production dependencies,
# reduce node_module size with modclean & removing sqlite deps, # reduce node_module size with modclean & removing sqlite deps,

20
packages/nocodb/package-lock.json generated

@ -1,12 +1,12 @@
{ {
"name": "nocodb", "name": "nocodb",
"version": "0.107.3", "version": "0.107.4",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "nocodb", "name": "nocodb",
"version": "0.107.3", "version": "0.107.4",
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"dependencies": { "dependencies": {
"@google-cloud/storage": "^5.7.2", "@google-cloud/storage": "^5.7.2",
@ -80,7 +80,7 @@
"mysql2": "^3.2.0", "mysql2": "^3.2.0",
"nanoid": "^3.1.20", "nanoid": "^3.1.20",
"nc-help": "^0.2.87", "nc-help": "^0.2.87",
"nc-lib-gui": "0.107.3", "nc-lib-gui": "0.107.4",
"nc-plugin": "^0.1.3", "nc-plugin": "^0.1.3",
"ncp": "^2.0.0", "ncp": "^2.0.0",
"nocodb-sdk": "file:../nocodb-sdk", "nocodb-sdk": "file:../nocodb-sdk",
@ -190,7 +190,7 @@
} }
}, },
"../nocodb-sdk": { "../nocodb-sdk": {
"version": "0.107.3", "version": "0.107.4",
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"dependencies": { "dependencies": {
"axios": "^0.21.1", "axios": "^0.21.1",
@ -13157,9 +13157,9 @@
} }
}, },
"node_modules/nc-lib-gui": { "node_modules/nc-lib-gui": {
"version": "0.107.3", "version": "0.107.4",
"resolved": "https://registry.npmjs.org/nc-lib-gui/-/nc-lib-gui-0.107.3.tgz", "resolved": "https://registry.npmjs.org/nc-lib-gui/-/nc-lib-gui-0.107.4.tgz",
"integrity": "sha512-U/GEGt4AFIIA0W1uD5nzG9drWrwdZjj1V1AFTNXdXECqpW3tshev6IFJhBOPXNl7QbXR3POAfZLW3x/IUjQZ7Q==", "integrity": "sha512-+e0jjJgrBfgLGTTShkcu1QQ2I0QxE/NUCCJ5L8KeZibm71pvgxL/P2hfatSz8PvzSDU/YwXnyXZQkeaSDBzNyA==",
"dependencies": { "dependencies": {
"express": "^4.17.1" "express": "^4.17.1"
} }
@ -28442,9 +28442,9 @@
} }
}, },
"nc-lib-gui": { "nc-lib-gui": {
"version": "0.107.3", "version": "0.107.4",
"resolved": "https://registry.npmjs.org/nc-lib-gui/-/nc-lib-gui-0.107.3.tgz", "resolved": "https://registry.npmjs.org/nc-lib-gui/-/nc-lib-gui-0.107.4.tgz",
"integrity": "sha512-U/GEGt4AFIIA0W1uD5nzG9drWrwdZjj1V1AFTNXdXECqpW3tshev6IFJhBOPXNl7QbXR3POAfZLW3x/IUjQZ7Q==", "integrity": "sha512-+e0jjJgrBfgLGTTShkcu1QQ2I0QxE/NUCCJ5L8KeZibm71pvgxL/P2hfatSz8PvzSDU/YwXnyXZQkeaSDBzNyA==",
"requires": { "requires": {
"express": "^4.17.1" "express": "^4.17.1"
} }

4
packages/nocodb/package.json

@ -1,6 +1,6 @@
{ {
"name": "nocodb", "name": "nocodb",
"version": "0.107.3", "version": "0.107.4",
"description": "NocoDB Backend", "description": "NocoDB Backend",
"main": "dist/bundle.js", "main": "dist/bundle.js",
"author": { "author": {
@ -113,7 +113,7 @@
"mysql2": "^3.2.0", "mysql2": "^3.2.0",
"nanoid": "^3.1.20", "nanoid": "^3.1.20",
"nc-help": "^0.2.87", "nc-help": "^0.2.87",
"nc-lib-gui": "0.107.3", "nc-lib-gui": "0.107.4",
"nc-plugin": "^0.1.3", "nc-plugin": "^0.1.3",
"ncp": "^2.0.0", "ncp": "^2.0.0",
"nocodb-sdk": "file:../nocodb-sdk", "nocodb-sdk": "file:../nocodb-sdk",

2
packages/nocodb/src/Noco.ts

@ -1,5 +1,6 @@
import Sentry, { Handlers } from '@sentry/node'; import Sentry, { Handlers } from '@sentry/node';
import { Logger } from '@nestjs/common'; import { Logger } from '@nestjs/common';
import path from 'path';
import { NestFactory } from '@nestjs/core'; import { NestFactory } from '@nestjs/core';
import clear from 'clear'; import clear from 'clear';
import * as express from 'express'; import * as express from 'express';
@ -122,6 +123,7 @@ export default class Noco {
const dashboardPath = process.env.NC_DASHBOARD_URL || '/dashboard'; const dashboardPath = process.env.NC_DASHBOARD_URL || '/dashboard';
server.use(NcToolGui.expressMiddleware(dashboardPath)); server.use(NcToolGui.expressMiddleware(dashboardPath));
server.use(express.static(path.join(__dirname, 'public')));
server.get('/', (_req, res) => res.redirect(dashboardPath)); server.get('/', (_req, res) => res.redirect(dashboardPath));
this.initSentryErrorHandler(server); this.initSentryErrorHandler(server);

3
packages/nocodb/src/app.module.ts

@ -5,7 +5,6 @@ import { EventEmitterModule as NestJsEventEmitter } from '@nestjs/event-emitter'
import { GlobalExceptionFilter } from './filters/global-exception/global-exception.filter'; import { GlobalExceptionFilter } from './filters/global-exception/global-exception.filter';
import { GlobalMiddleware } from './middlewares/global/global.middleware'; import { GlobalMiddleware } from './middlewares/global/global.middleware';
import { GuiMiddleware } from './middlewares/gui/gui.middleware'; import { GuiMiddleware } from './middlewares/gui/gui.middleware';
import { PublicMiddleware } from './middlewares/public/public.middleware';
import { DatasModule } from './modules/datas/datas.module'; import { DatasModule } from './modules/datas/datas.module';
import { EventEmitterModule } from './modules/event-emitter/event-emitter.module'; import { EventEmitterModule } from './modules/event-emitter/event-emitter.module';
import { AuthService } from './services/auth.service'; import { AuthService } from './services/auth.service';
@ -59,8 +58,6 @@ export class AppModule {
consumer consumer
.apply(GuiMiddleware) .apply(GuiMiddleware)
.forRoutes({ path: '*', method: RequestMethod.GET }) .forRoutes({ path: '*', method: RequestMethod.GET })
.apply(PublicMiddleware)
.forRoutes({ path: '*', method: RequestMethod.GET })
.apply(GlobalMiddleware) .apply(GlobalMiddleware)
.forRoutes({ path: '*', method: RequestMethod.ALL }); .forRoutes({ path: '*', method: RequestMethod.ALL });
} }

281
packages/nocodb/src/helpers/initAdminFromEnv.ts

@ -0,0 +1,281 @@
import { promisify } from 'util';
import { v4 as uuidv4 } from 'uuid';
import bcrypt from 'bcryptjs';
import { validatePassword } from 'nocodb-sdk';
import boxen from 'boxen';
import { T } from 'nc-help';
import { isEmail } from 'validator';
import NocoCache from '../cache/NocoCache';
import { ProjectUser, User } from '../models';
import Noco from '../Noco';
import { CacheScope, MetaTable } from '../utils/globals';
const rolesLevel = { owner: 0, creator: 1, editor: 2, commenter: 3, viewer: 4 };
export default async function initAdminFromEnv(_ncMeta = Noco.ncMeta) {
if (process.env.NC_ADMIN_EMAIL && process.env.NC_ADMIN_PASSWORD) {
if (!isEmail(process.env.NC_ADMIN_EMAIL?.trim())) {
console.log(
'\n',
boxen(
`Provided admin email '${process.env.NC_ADMIN_EMAIL}' is not valid`,
{
title: 'Invalid admin email',
padding: 1,
borderStyle: 'double',
titleAlignment: 'center',
borderColor: 'red',
},
),
'\n',
);
process.exit(1);
}
const { valid, error, hint } = validatePassword(
process.env.NC_ADMIN_PASSWORD,
);
if (!valid) {
console.log(
'\n',
boxen(`${error}${hint ? `\n\n${hint}` : ''}`, {
title: 'Invalid admin password',
padding: 1,
borderStyle: 'double',
titleAlignment: 'center',
borderColor: 'red',
}),
'\n',
);
process.exit(1);
}
let ncMeta;
try {
ncMeta = await _ncMeta.startTransaction();
const email = process.env.NC_ADMIN_EMAIL.toLowerCase().trim();
const salt = await promisify(bcrypt.genSalt)(10);
const password = await promisify(bcrypt.hash)(
process.env.NC_ADMIN_PASSWORD,
salt,
);
const email_verification_token = uuidv4();
const roles = 'user,super';
// if super admin not present
if (await User.isFirst(ncMeta)) {
// roles = 'owner,creator,editor'
T.emit('evt', {
evt_type: 'project:invite',
count: 1,
});
await User.insert(
{
firstname: '',
lastname: '',
email,
salt,
password,
email_verification_token,
roles,
},
ncMeta,
);
} else {
const salt = await promisify(bcrypt.genSalt)(10);
const password = await promisify(bcrypt.hash)(
process.env.NC_ADMIN_PASSWORD,
salt,
);
const email_verification_token = uuidv4();
const superUser = await ncMeta.metaGet2(null, null, MetaTable.USERS, {
roles: 'user,super',
});
if (!superUser?.id) {
const existingUserWithNewEmail = await User.getByEmail(email, ncMeta);
if (existingUserWithNewEmail?.id) {
// clear cache
await NocoCache.delAll(
CacheScope.USER,
`${existingUserWithNewEmail.email}___*`,
);
await NocoCache.del(
`${CacheScope.USER}:${existingUserWithNewEmail.id}`,
);
await NocoCache.del(
`${CacheScope.USER}:${existingUserWithNewEmail.email}`,
);
// Update email and password of super admin account
await User.update(
existingUserWithNewEmail.id,
{
salt,
email,
password,
email_verification_token,
token_version: null,
refresh_token: null,
roles,
},
ncMeta,
);
} else {
T.emit('evt', {
evt_type: 'project:invite',
count: 1,
});
await User.insert(
{
firstname: '',
lastname: '',
email,
salt,
password,
email_verification_token,
roles,
},
ncMeta,
);
}
} else if (email !== superUser.email) {
// update admin email and password and migrate projects
// if user already present and associated with some project
// check user account already present with the new admin email
const existingUserWithNewEmail = await User.getByEmail(email, ncMeta);
if (existingUserWithNewEmail?.id) {
// get all project access belongs to the existing account
// and migrate to the admin account
const existingUserProjects = await ncMeta.metaList2(
null,
null,
MetaTable.PROJECT_USERS,
{
condition: { fk_user_id: existingUserWithNewEmail.id },
},
);
for (const existingUserProject of existingUserProjects) {
const userProject = await ProjectUser.get(
existingUserProject.project_id,
superUser.id,
ncMeta,
);
// if admin user already have access to the project
// then update role based on the highest access level
if (userProject) {
if (
rolesLevel[userProject.roles] >
rolesLevel[existingUserProject.roles]
) {
await ProjectUser.update(
userProject.project_id,
superUser.id,
existingUserProject.roles,
ncMeta,
);
}
} else {
// if super doesn't have access then add the access
await ProjectUser.insert(
{
...existingUserProject,
fk_user_id: superUser.id,
},
ncMeta,
);
}
// delete the old project access entry from DB
await ProjectUser.delete(
existingUserProject.project_id,
existingUserProject.fk_user_id,
ncMeta,
);
}
// delete existing user
await ncMeta.metaDelete(
null,
null,
MetaTable.USERS,
existingUserWithNewEmail.id,
);
// clear cache
await NocoCache.delAll(
CacheScope.USER,
`${existingUserWithNewEmail.email}___*`,
);
await NocoCache.del(
`${CacheScope.USER}:${existingUserWithNewEmail.id}`,
);
await NocoCache.del(
`${CacheScope.USER}:${existingUserWithNewEmail.email}`,
);
// Update email and password of super admin account
await User.update(
superUser.id,
{
salt,
email,
password,
email_verification_token,
token_version: null,
refresh_token: null,
},
ncMeta,
);
} else {
// if email's are not different update the password and hash
await User.update(
superUser.id,
{
salt,
email,
password,
email_verification_token,
token_version: null,
refresh_token: null,
},
ncMeta,
);
}
} else {
const newPasswordHash = await promisify(bcrypt.hash)(
process.env.NC_ADMIN_PASSWORD,
superUser.salt,
);
if (newPasswordHash !== superUser.password) {
// if email's are same and passwords are different
// then update the password and token version
await User.update(
superUser.id,
{
salt,
password,
email_verification_token,
token_version: null,
refresh_token: null,
},
ncMeta,
);
}
}
}
await ncMeta.commit();
} catch (e) {
console.log('Error occurred while updating/creating admin user');
console.log(e);
await ncMeta.rollback(e);
}
}
}

7
packages/nocodb/src/middlewares/public/public.middleware.spec.ts

@ -1,7 +0,0 @@
import { PublicMiddleware } from './public.middleware';
describe('PublicMiddleware', () => {
it('should be defined', () => {
expect(new PublicMiddleware()).toBeDefined();
});
});

23
packages/nocodb/src/middlewares/public/public.middleware.ts

@ -1,23 +0,0 @@
import path, { join } from 'path';
import { Injectable } from '@nestjs/common';
import express from 'express';
import isDocker from 'is-docker';
import type { NestMiddleware } from '@nestjs/common';
@Injectable()
export class PublicMiddleware implements NestMiddleware {
use(req: any, res: any, next: () => void) {
// redirect root to dashboard
if (req.path === '/') {
const dashboardPath = process.env.NC_DASHBOARD_URL || '/dashboard';
return res.redirect(dashboardPath);
}
// serve static files from public folder
if (isDocker()) {
express.static(join(process.cwd(), 'docker', 'public'))(req, res, next);
} else {
express.static(join(process.cwd(), 'public'))(req, res, next);
}
}
}

0
packages/nocodb/public/css/fonts.montserrat.css → packages/nocodb/src/public/css/fonts.montserrat.css

0
packages/nocodb/public/css/fonts.roboto.css → packages/nocodb/src/public/css/fonts.roboto.css

0
packages/nocodb/public/css/materialdesignicons.5.x.min.css → packages/nocodb/src/public/css/materialdesignicons.5.x.min.css vendored

0
packages/nocodb/public/css/swagger-ui-bundle.4.5.2.min.css → packages/nocodb/src/public/css/swagger-ui-bundle.4.5.2.min.css vendored

0
packages/nocodb/public/css/vuetify.2.x.min.css → packages/nocodb/src/public/css/vuetify.2.x.min.css vendored

0
packages/nocodb/public/favicon.ico → packages/nocodb/src/public/favicon.ico

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

0
packages/nocodb/public/icon.png → packages/nocodb/src/public/icon.png

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

0
packages/nocodb/public/js/axios.0.19.2.min.js → packages/nocodb/src/public/js/axios.0.19.2.min.js vendored

0
packages/nocodb/public/js/redoc.standalone.min.js → packages/nocodb/src/public/js/redoc.standalone.min.js vendored

0
packages/nocodb/public/js/swagger-ui-bundle.4.5.2.min.js → packages/nocodb/src/public/js/swagger-ui-bundle.4.5.2.min.js vendored

0
packages/nocodb/public/js/vue.2.6.14.min.js → packages/nocodb/src/public/js/vue.2.6.14.min.js vendored

0
packages/nocodb/public/js/vue.global.js → packages/nocodb/src/public/js/vue.global.js

0
packages/nocodb/public/js/vuetify.2.x.min.js → packages/nocodb/src/public/js/vuetify.2.x.min.js vendored

13
packages/nocodb/src/services/app-init.service.ts

@ -1,9 +1,12 @@
import { Inject, Injectable } from '@nestjs/common'; import { T } from 'nc-help';
import NocoCache from '../cache/NocoCache'; import NocoCache from '../cache/NocoCache';
import { Connection } from '../connection/connection'; import { Connection } from '../connection/connection';
import initAdminFromEnv from '../helpers/initAdminFromEnv';
import NcPluginMgrv2 from '../helpers/NcPluginMgrv2'; import NcPluginMgrv2 from '../helpers/NcPluginMgrv2';
import { MetaService } from '../meta/meta.service'; import { MetaService } from '../meta/meta.service';
import { User } from '../models'
import Noco from '../Noco'; import Noco from '../Noco';
import getInstance from '../utils/getInstance';
import NcConfigFactory from '../utils/NcConfigFactory'; import NcConfigFactory from '../utils/NcConfigFactory';
import NcUpgrader from '../version-upgrader/NcUpgrader'; import NcUpgrader from '../version-upgrader/NcUpgrader';
import type { IEventEmitter } from '../modules/event-emitter/event-emitter.interface'; import type { IEventEmitter } from '../modules/event-emitter/event-emitter.interface';
@ -54,6 +57,9 @@ export const appInitServiceProvider: Provider = {
// init jwt secret // init jwt secret
await Noco.initJwt(); await Noco.initJwt();
// load super admin user from env if env is set
await initAdminFromEnv(metaService);
// init plugin manager // init plugin manager
await NcPluginMgrv2.init(Noco.ncMeta); await NcPluginMgrv2.init(Noco.ncMeta);
await Noco.loadEEState(); await Noco.loadEEState();
@ -61,6 +67,11 @@ export const appInitServiceProvider: Provider = {
// run upgrader // run upgrader
await NcUpgrader.upgrade({ ncMeta: Noco._ncMeta }); await NcUpgrader.upgrade({ ncMeta: Noco._ncMeta });
T.init({
instance: getInstance,
});
T.emit('evt_app_started', await User.count());
// todo: move app config to app-init service // todo: move app config to app-init service
return new AppInitService(connection.config); return new AppInitService(connection.config);
}, },

2
packages/nocodb/webpack.config.js

@ -44,7 +44,7 @@ module.exports = {
plugins: [ plugins: [
new webpack.EnvironmentPlugin(['EE']), new webpack.EnvironmentPlugin(['EE']),
new CopyPlugin({ new CopyPlugin({
patterns: [{ from: 'public', to: 'public' }], patterns: [{ from: 'src/public', to: 'public' }],
}), }),
], ],

Loading…
Cancel
Save