/**
* Create a database (schema) & a minimal set of DB object for a UnityBase ORM
* Will first create a temporary config with authentication disabled and
* @example
*
//from a command line
>ub cmd/initDB -u admin -p admin -dba postgres -dbaPwd postgreDBAPassword
//from a code
var initDB = require('cmd/initDB');
var options = {
"host": "http://localhost:888",
"user": "admin",
"pwd": "admin",
"clientIdentifier": 3,
"dropDatabase": true,
"createDatabase": true,
"dba": "postgres",
"dbaPwd": "postgreDBAPassword"
};
initDB(options);
* @module cmd/initDB
*/
var cmdLineOpt = require('cmd/options');
/**
* If DBA already create a database for you set both `dropDatabase` & `createDatabase` to false
* @param {Object} options
* @param {Number} [options.clientIdentifier=3] Identifier of the client.
* Must be between 2 and 8999. Number 1 is for UnityBase developer, 3 for test.
* Numbers > 100 is for real installations
* @param {Boolean} [options.dropDatabase=false] Drop a database/schema first
* @param {Boolean} [options.createDatabase=false] Create a new database/schema.
* @param {String} [options.dba] A DBA name. Used in case `createDatabase=true`
* @param {String} [options.dbaPwd] A DBA password. Used in case `createDatabase=true`
*/
module.exports = function initDB(options){
var argv = require('cmd/argv');
var fs = require('fs');
if (!options){
var opts = cmdLineOpt.describe('cmd/initDB', 'Prepare a new database for a UB ORM')
.add(argv.establishConnectionFromCmdLineAttributes._cmdLineParams)
.add({short: 'c', long: 'clientIdentifier', param: 'clientIdentifier',defaultValue: 3, searchInEnv: false, help: 'Identifier of the client'})
.add({short: 'drop', long: 'dropDatabase', param: '', defaultValue: false, searchInEnv: false, help: 'Drop a database/schema first'})
.add({short: 'create',long: 'createDatabase', param: '', defaultValue: false, searchInEnv: false, help: 'Create a new database/schema'})
.add({short: 'dba', long: 'dba', param: 'DBA_user_name', defaultValue: '-', searchInEnv: false, help: 'A DBA name. Used in case `createDatabase=true`'})
.add({short: 'dbaPwd',long: 'dbaPwd', param: 'DBA_password', defaultValue: '-', searchInEnv: false, help: 'A DBA password. Used in case `createDatabase=true`'});
options = opts.parseVerbose({}, true);
}
if (!options) return;
var session, conn, defaultDB, generator;
var originalConfigFileName = argv.getConfigFileName();
var config = argv.getServerConfiguration();
options.host = argv.serverURLFromConfig(config);
// database are slow :( Increase timeout to 2 minutes
var http = require('http');
http.setGlobalConnectionDefaults({receiveTimeout: 2 * 60 * 1000});
if (argv.checkServerStarted(options.host)){
// throw new Error('Please, shutdown a server on ' + options.host + ' before run this command');
}
fs.renameSync(originalConfigFileName, originalConfigFileName + '.bak');
try {
defaultDB = createFakeConfig(config, originalConfigFileName);
options.forceStartServer = true;
session = argv.establishConnectionFromCmdLineAttributes(options);
conn = session.connection;
var dbDriverName = defaultDB.driver.toLowerCase();
if (dbDriverName.startsWith('mssql')) {
dbDriverName = 'mssql';
}
generator = require('./' + dbDriverName);
if (options.dropDatabase) {
console.info('Dropping a database...');
generator.dropDatabase(session, defaultDB);
}
if (options.createDatabase) {
console.info('Creating a database...');
generator.createDatabase(conn, defaultDB);
}
console.info('Creating a minimal set of database objects...');
generator.createMinSchema(conn, options.clientIdentifier, defaultDB);
console.info('Creating a superuser..');
createSuperUser(conn, dbDriverName);
console.info('Database is ready. Run a `cmd/generateDDL` command to create a database tables for a domain');
} finally {
fs.renameSync(originalConfigFileName + '.bak', originalConfigFileName);
}
/**
* Create a fake config with authentication disabled & empty domain.
* Return a default database driver name
*/
function createFakeConfig(){
var defaultDB = _.find(config.application.connections, {isDefault: true}) || config.application.connections[0];
var newConfig = _.cloneDeep(config);
var dbaConn;
newConfig.security = {};
newConfig.application.domain = {};
if (options.dropDatabase || options.createDatabase){
dbaConn = _.cloneDeep(defaultDB);
_.assign(dbaConn, {
name: '__dba',
userID: options.dba,
password: options.dbaPwd,
isDefault: false
});
if (dbaConn.driver.toLowerCase().startsWith('mssql')){
dbaConn.databaseName = 'master';
}
newConfig.httpServer.threadPoolSize = 1;
newConfig.application.connections.push(dbaConn);
}
fs.writeFileSync(originalConfigFileName, newConfig);
// uncomment for debug purpose
// fs.writeFileSync(originalConfigFileName + '.fake', JSON.stringify(newConfig, null, '\t'));
return defaultDB;
}
};
/**
* Create a Everyone & admin roles and a SuperUser named admin with password `admin`
* @param {UBConnection} conn
* @param {String} dbDriverName
*/
function createSuperUser(conn, dbDriverName) {
var pwdHash = nsha256('salt' + 'admin');
var initSecurity;
if (dbDriverName === 'sqlite3'){
var isoDate = "'" + new Date().toISOString().slice(0, -5) + "Z'";
var auditTailFlds = 'mi_owner,mi_createdate,mi_createuser,mi_modifydate,mi_modifyuser';
var auditTailVals = "10," + isoDate + ",10," + isoDate + ",10";
initSecurity = [
"PRAGMA foreign_keys = OFF",
/* admins role */
"insert into uba_subject (ID,name,sType,mi_unityentity) values(1, 'admins', 'R', 'UBA_SUBJECT')",
"insert into uba_role (ID,name,description,sessionTimeout,allowedAppMethods," + auditTailFlds + ") values(1,'admins','UB application administrator',10,'*'," + auditTailVals + ")", /* user admin */
"insert into uba_subject (ID,name,sType,mi_unityentity) values(10 ,'admin', 'U', 'UBA_USER')",
"insert into uba_user (id, name, description, upasswordhashhexa, disabled, udata," + auditTailFlds + ") values (10, 'admin', 'admin', '" + pwdHash + "', 0, ''," + auditTailVals + ")",
/* Everyone pseudo-role */
"insert into uba_subject (ID,name,sType,mi_unityentity) values(0, 'Everyone', 'R', 'UBA_SUBJECT')",
"insert into uba_role (ID,name,description,sessionTimeout,allowedAppMethods," + auditTailFlds + ") values(0,'Everyone','Pseudo role. To use only in ELS rules',10000,'ubql,getDomainInfo,logout,getDocument,setDocument'," + auditTailVals + ")",
/* allow all for admins role (with ID = 1) */
"INSERT INTO uba_els (ID, code, description, disabled, entityMask, methodMask, ruleType, ruleRole," + auditTailFlds + ") VALUES (200, 'UBA_ADMIN_ALL', 'Admins - enable all', 0, '*', '*', 'A', 1," + auditTailVals + ")",
/* assign user admin to role admins */
"insert into uba_userrole (ID,userID, roleID," + auditTailFlds + ") values(800,10,1," + auditTailVals + ");",
"PRAGMA foreign_keys = ON"
];
} else {
initSecurity = [
/* Everyone pseudo-role */
"insert into uba_subject (ID,name,sType,mi_unityentity) values(0, 'Everyone', 'R', 'UBA_SUBJECT')",
"insert into uba_role (ID,name,description,sessionTimeout,allowedAppMethods) values(0,'Everyone','Pseudo role. To use only in ELS rules',10000,'ubql,getDomainInfo,logout,getDocument,setDocument')",
/* admins role */
"insert into uba_subject (ID,name,sType,mi_unityentity) values(1, 'admins', 'R', 'UBA_SUBJECT')",
"insert into uba_role (ID,name,description,sessionTimeout,allowedAppMethods) values(1,'admins','UB application administrator',10,'*')", /* user admin */
"insert into uba_subject (ID,name,sType,mi_unityentity) values(10 ,'admin', 'U', 'UBA_USER')",
"insert into uba_user (id, name, description, upasswordhashhexa, disabled, udata) values (10, 'admin', 'admin', '" + pwdHash + "', 0, '')",
/* allow all for admins role (with ID = 1) */
"INSERT INTO uba_els (ID, code, description, disabled, entityMask, methodMask, ruleType, ruleRole) VALUES (200, 'UBA_ADMIN_ALL', 'Admins - enable all', 0, '*', '*', 'A', 1)",
/* assign user admin to role admins */
"insert into uba_userrole (ID,userID, roleID) values(800,10,1);"
];
}
initSecurity.forEach(function(stmt){
conn.xhr({
endpoint: 'runSQL', URLParams: {CONNECTION: 'main'}, data: stmt
})
});
}