const Deferred = require("jQDeferred");
const _ = require('lodash');
const Q = require('./../client/components/metadata/jsDataQuery');
/**
* Identity class is declared in jsToken. Identity must have name,idflowchart,ndetail set
* @param {Identity} identity identity.name must match a username in the customuser table
* @constructor
*/
function Environment(identity) {
this.mySys = {};
this.myUsr = {};
this.fields = {};
this.stampFields = this.getStampFields();
this.sys("user",identity.name||this.getAnonymousName());
if (identity.isAnonymous){ //just to be sure
this.sys("user",this.getAnonymousName());
}
this.sys("idflowchart",identity.idflowchart||null);
this.sys("ndetail",identity.ndetail||null);
this.sys("esercizio",new Date().getFullYear());
this.sys("ayear",new Date().getFullYear());
}
Environment.prototype = {
constructor: Environment,
/**
* this is meant to be redefined in derived classes
* @return {string}
*/
getAnonymousName: function (){
return "anonymous";
}
};
/**
* Returns an array of fields used as stamp in evaluating field function for optimistic locking
* This function means to be redefined in derived classes
* @return {string[]}
*/
Environment.prototype.getStampFields =function(){
return ["ct","lt"];
};
/**
* Get/set a value for an environment sys variable
* @param {string} key
* @param {object} [value]
* @returns {object}
*/
Environment.prototype.sys = function (key, value) {
if (value !== undefined) {
this.mySys[key] = value;
return this;
}
return this.mySys[key];
};
/**
* Get a value for an environment field or a new Date if the field is a stamp field
* @param {string} key
* @param {object} [value]
* @returns {object}
*/
Environment.prototype.field = function (key, value) {
if (value !== undefined) {
this.fields[key] = value;
return this;
}
if (this.stampFields[key]) {
return new Date();
}
return this.fields[key];
};
/**
* Get/set a value for an environment usr variable
* @param {string} key
* @param {object} [value]
* @returns {object}
*/
Environment.prototype.usr = function (key, value) {
if (value !== undefined) {
this.myUsr[key] = value;
return this;
}
return this.myUsr[key];
};
/**
* Enumerates all sys keys
* @return {string[]}
*/
Environment.prototype.enumSys = function () {
return _.keys(this.mySys);
};
/**
* Enumerates all usr keys
* @return {string[]}
*/
Environment.prototype.enumUsr = function () {
return _.keys(this.myUsr);
};
function defaultQuoter(s, noSurroundQuotes) {
if (noSurroundQuotes) {
if (s === null || s === undefined) {
return 'null';
}
if (typeof s === 'string' || s instanceof String) {
return s;
}
return s.toString();
}
if (s === null || s === undefined) {
return 'null';
}
if (typeof s === 'string' || s instanceof String) {
return "'" + s.replace("'", "\\'") + "'";
}
return s.toString();
}
/**
* Evaluates env.sys[idcustomuser], requires env.sys[user] to be already defined
* @public
* @param {DataAccess} conn
* @return {Promise<object>}
*/
Environment.prototype.getCustomUser= function(conn){
let d = Deferred();
if (this.sys("idcustomuser")) {
return d.resolve(this.sys("idcustomuser"));
}
conn.readSingleValue({
tableName:"customuser",
expr:"idcustomuser",
filter:Q.eq("username",this.sys("user"))
})
.then(idcustomuser =>{
this.sys("idcustomuser",idcustomuser);
d.resolve(idcustomuser);
});
return d.promise();
};
/**
* Evaluates env.sys[usergrouplist], requires env.sys[user] to be already defined.
* This is meant to be invoked when environment is created
* @static
* @param {DataAccess} conn
* @return {Promise<Array.<object>>}
*/
Environment.prototype.getGroupList = function(conn) {
let d = Deferred();
if (this.usr("usergrouplist")) {
return d.resolve(this.sys("usergrouplist"));
}
this.getCustomUser(conn)
.then(idcustomuser=> {
if (!idcustomuser){
this.sys("usergrouplist",[]);
d.resolve([]);
return;
}
conn.select({
tableName: "customusergroup",
filter: Q.eq("idcustomuser", idcustomuser)
})
.then(t => {
let res = _.reduce(t, function (result, r) {
result.push(r.idcustomgroup);
return result;
}, []);
this.usr("usergrouplist", res);
d.resolve(res);
});
});
return d.promise();
};
function quote(s){
if (typeof s !== "string") {
return s;
}
return "'"+s.replace(new RegExp("'", 'g'), "''")+"'";
}
/**
* invokes a stored procedure to compute environment, needs sys(idcustomuser)
* @param {DataAccess} conn
* @return {Promise}
*/
Environment.prototype.calcUserEnvironment = function(conn) {
return conn.callSP("compute_environment",
[this.sys("esercizio"),this.sys("idcustomuser"),
this.sys("idflowchart")||null,this.sys("ndetail")||null])
.then(res=>{
if (!res){
return Deferred().reject("No environment");
}
if (res.length !== 2){
console.log(res);
return Deferred().reject("Bad environment");
}
let sysVars= res[0][0];
_.forOwn(sysVars,(value,key)=>{
this.sys(key,this.compile(value));
});
let usrVars = res[1];
usrVars.forEach(rUsr => {
if (rUsr.mustquote.toUpperCase() === "S") {
this.usr(rUsr.variablename, this.compile(quote(rUsr.value)));
}
else {
this.usr(rUsr.variablename, this.compile(rUsr.value));
}
});
return Deferred().resolve(true);
});
};
Environment.prototype.compile = function (str, quoteFun, surroundQuotes) {
if (typeof str !== "string") {
return str;
}
quoteFun = quoteFun || defaultQuoter;
if (surroundQuotes === undefined) {
surroundQuotes = false;
}
var s = '',
prev = '',
that = this,
replaceSys = function (match, p1) {
return quoteFun(that.mySys[p1], !surroundQuotes);
},
replaceUsr = function (match, p1) {
return quoteFun(that.myUsr[p1], !surroundQuotes);
};
while (prev !== str) {
prev = str;
s = str.replace(/(?:<%sys\[)[\s]*([\w]+)[\s]*(?:\]%>)/g, replaceSys);
s = s.replace(/(?:<%usr\[)[\s]*([\w]+)[\s]*(?:\]%>)/g, replaceUsr);
str = s;
}
return s;
};
Environment.prototype.compileFun = function(sqlFun,formatter) {
return sqlFun.toSql(formatter,this);
};
/**
* Loads environment from a database, it needs sys(user) and eventually idflowchart and ndetail
* to be present in sys variables
* @param {DataAccess} conn
* @return {Promise}
*/
Environment.prototype.load = function(conn){
return this.getGroupList(conn)
.then(()=>{
return this.calcUserEnvironment(conn);
});
};
module.exports = Environment;