mirror of https://github.com/nocodb/nocodb
nith2001
2 years ago
committed by
GitHub
197 changed files with 16300 additions and 9042 deletions
@ -1,19 +0,0 @@
|
||||
import { Test } from '@nestjs/testing'; |
||||
import { Connection } from './knex'; |
||||
import type { TestingModule } from '@nestjs/testing'; |
||||
|
||||
describe('Knex', () => { |
||||
let provider: Connection; |
||||
|
||||
beforeEach(async () => { |
||||
const module: TestingModule = await Test.createTestingModule({ |
||||
providers: [Connection], |
||||
}).compile(); |
||||
|
||||
provider = module.get<Connection>(Connection); |
||||
}); |
||||
|
||||
it('should be defined', () => { |
||||
expect(provider).toBeDefined(); |
||||
}); |
||||
}); |
@ -1,37 +0,0 @@
|
||||
import { Global, Injectable, Scope } from '@nestjs/common'; |
||||
|
||||
import { XKnex } from '../db/CustomKnex'; |
||||
import NcConfigFactory from '../utils/NcConfigFactory'; |
||||
import type * as knex from 'knex'; |
||||
|
||||
@Injectable({ |
||||
scope: Scope.DEFAULT, |
||||
}) |
||||
export class Connection { |
||||
public static knex: knex.Knex; |
||||
public static _config: any; |
||||
|
||||
get knexInstance(): knex.Knex { |
||||
return Connection.knex; |
||||
} |
||||
|
||||
get config(): knex.Knex { |
||||
return Connection._config; |
||||
} |
||||
|
||||
// init metadb connection
|
||||
static async init(): Promise<void> { |
||||
Connection._config = await NcConfigFactory.make(); |
||||
if (!Connection.knex) { |
||||
Connection.knex = XKnex({ |
||||
...this._config.meta.db, |
||||
useNullAsDefault: true, |
||||
}); |
||||
} |
||||
} |
||||
|
||||
// init metadb connection
|
||||
async init(): Promise<void> { |
||||
return await Connection.init(); |
||||
} |
||||
} |
@ -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); |
||||
} |
||||
} |
||||
} |
@ -1,6 +1,5 @@
|
||||
import Noco from './Noco'; |
||||
import NcConfigFactory from './utils/NcConfigFactory'; |
||||
|
||||
export default Noco; |
||||
|
||||
export { Noco, NcConfigFactory }; |
||||
export { Noco }; |
||||
|
@ -1,12 +1,12 @@
|
||||
import { Connection } from './connection/connection'; |
||||
import { MetaService } from './meta/meta.service'; |
||||
import { NcConfig } from './utils/nc-config'; |
||||
import Noco from './Noco'; |
||||
|
||||
// run upgrader
|
||||
import NcUpgrader from './version-upgrader/NcUpgrader'; |
||||
|
||||
export default async () => { |
||||
await Connection.init(); |
||||
Noco._ncMeta = new MetaService(new Connection()); |
||||
const config = await NcConfig.createByEnv(); |
||||
Noco._ncMeta = new MetaService(config); |
||||
await NcUpgrader.upgrade({ ncMeta: Noco._ncMeta }); |
||||
}; |
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue