jsharmony 1.7.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +10 -3
- package/.eslintrc_clientjs.js +46 -0
- package/.eslintrc_test.js +51 -0
- package/AppSrv.DB.js +2 -2
- package/AppSrv.File.js +1 -3
- package/AppSrv.Helper.js +9 -9
- package/AppSrv.ModelExec.js +6 -10
- package/AppSrv.ModelForm.js +25 -23
- package/AppSrv.ModelGrid.js +20 -21
- package/AppSrv.ModelMetadata.js +36 -39
- package/AppSrv.ModelMultisel.js +13 -16
- package/AppSrv.Queue.js +4 -4
- package/AppSrv.Report.js +16 -16
- package/AppSrv.js +20 -21
- package/AppSrvModel.js +40 -41
- package/AppSrvRpt.js +65 -81
- package/AppSrvTask.js +56 -57
- package/clientjs/JSHFind.js +10 -10
- package/clientjs/XAPI.Form.js +29 -28
- package/clientjs/XAPI.Grid.js +30 -30
- package/clientjs/XAPI.js +2 -2
- package/clientjs/XBarcode.js +6 -5
- package/clientjs/XDebugConsole.js +54 -55
- package/clientjs/XEditableGrid.js +35 -39
- package/clientjs/XExt.XModel.js +48 -57
- package/clientjs/XExt.js +421 -412
- package/clientjs/XForm.js +85 -85
- package/clientjs/XFormat.js +74 -75
- package/clientjs/XGrid.js +50 -39
- package/clientjs/XImageLoader.js +2 -1
- package/clientjs/XLoader.js +8 -5
- package/clientjs/XMenu.js +47 -46
- package/clientjs/XPayment.js +4 -5
- package/clientjs/XScanner.js +4 -3
- package/clientjs/XSearch.js +13 -12
- package/clientjs/jsHarmony.js +66 -67
- package/init/install.app.config.local.js +9 -7
- package/jsHarmony.Helper.js +85 -80
- package/jsHarmony.LoadModels.js +63 -63
- package/jsHarmony.LoadSQL.js +10 -18
- package/jsHarmony.LoadTasks.js +8 -13
- package/jsHarmony.LoadViews.js +2 -2
- package/jsHarmony.Render.js +7 -7
- package/jsHarmony.js +2 -2
- package/jsHarmonyConfig.js +3 -3
- package/jsHarmonyExtensions.js +16 -16
- package/jsHarmonyModule.js +5 -6
- package/jsHarmonyModuleTransform.js +13 -13
- package/jsHarmonyServer.js +23 -19
- package/jsHarmonySite.js +9 -9
- package/jsHarmonyTranslator.js +12 -12
- package/lib/Auth.js +25 -23
- package/lib/CLI.js +34 -28
- package/lib/CodeGen.Models.js +35 -38
- package/lib/CodeGen.SQLObjects.js +17 -20
- package/lib/CodeGen.Schema.js +2 -4
- package/lib/CodeGen.js +1 -1
- package/lib/Helper.js +169 -170
- package/lib/HelperFS.js +29 -31
- package/lib/HelperRender.js +6 -10
- package/lib/JSParser.js +72 -56
- package/lib/JSScanner.js +14 -14
- package/lib/JSToken.js +15 -15
- package/lib/Logger.js +40 -46
- package/lib/Mailer.js +3 -1
- package/lib/WebConnect.js +11 -11
- package/lib/ejsext.js +78 -78
- package/lint.cmd +7 -0
- package/package.json +1 -1
- package/public/js/jsHarmony.js +1 -1
- package/render/RenderLogin.js +5 -12
- package/render/RenderLoginForgotPassword.js +15 -17
- package/render/RenderLoginForgotPasswordReset.js +5 -7
- package/render/RenderTemplate.js +3 -4
- package/routes/jsHarmonyRouter.js +54 -53
- package/sql/datatypes.sqlite.json +2 -2
- package/test/ValidateSubnet.js +1 -1
- package/test/images.js +4 -4
- package/test/index.js +2 -2
- package/test/modelTransforms.js +39 -39
- package/test/parser.js +0 -1
- package/test/websocket.js +4 -3
- package/test/xformat.js +0 -1
package/.eslintrc.js
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
module.exports = {
|
|
2
2
|
"env": {
|
|
3
3
|
"browser": true,
|
|
4
|
-
"node": true
|
|
4
|
+
"node": true,
|
|
5
|
+
"es6": true,
|
|
5
6
|
},
|
|
6
|
-
"extends":
|
|
7
|
+
"extends": [
|
|
8
|
+
"eslint:recommended",
|
|
9
|
+
],
|
|
7
10
|
"parserOptions": {
|
|
8
|
-
"ecmaVersion":
|
|
11
|
+
"ecmaVersion": 8
|
|
9
12
|
},
|
|
10
13
|
"rules": {
|
|
14
|
+
"no-trailing-spaces":[
|
|
15
|
+
"error",
|
|
16
|
+
{ "skipBlankLines": true }
|
|
17
|
+
],
|
|
11
18
|
"indent": [
|
|
12
19
|
"error",
|
|
13
20
|
2,
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
"env": {
|
|
3
|
+
"browser": true,
|
|
4
|
+
},
|
|
5
|
+
"plugins": [
|
|
6
|
+
"es5"
|
|
7
|
+
],
|
|
8
|
+
"extends": [
|
|
9
|
+
"eslint:recommended",
|
|
10
|
+
"plugin:es5/no-es2015"
|
|
11
|
+
],
|
|
12
|
+
"rules": {
|
|
13
|
+
"no-trailing-spaces":[
|
|
14
|
+
"error",
|
|
15
|
+
{ "skipBlankLines": true }
|
|
16
|
+
],
|
|
17
|
+
"indent": [
|
|
18
|
+
"error",
|
|
19
|
+
2,
|
|
20
|
+
{ "SwitchCase":1 }
|
|
21
|
+
],
|
|
22
|
+
"linebreak-style": [
|
|
23
|
+
"error",
|
|
24
|
+
"windows"
|
|
25
|
+
],
|
|
26
|
+
"quotes": [
|
|
27
|
+
"error",
|
|
28
|
+
"single",
|
|
29
|
+
{ "avoidEscape": true }
|
|
30
|
+
],
|
|
31
|
+
"semi": [
|
|
32
|
+
"error",
|
|
33
|
+
"always"
|
|
34
|
+
],
|
|
35
|
+
"no-unused-vars": [
|
|
36
|
+
"error",
|
|
37
|
+
{
|
|
38
|
+
"args": "none"
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
"no-cond-assign": [
|
|
42
|
+
"error",
|
|
43
|
+
"except-parens"
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
"env": {
|
|
3
|
+
"browser": true,
|
|
4
|
+
},
|
|
5
|
+
"plugins": [
|
|
6
|
+
"es5"
|
|
7
|
+
],
|
|
8
|
+
"extends": [
|
|
9
|
+
"eslint:recommended"
|
|
10
|
+
],
|
|
11
|
+
"globals": {
|
|
12
|
+
"it": "readonly",
|
|
13
|
+
"describe": "readonly",
|
|
14
|
+
"after": "readonly",
|
|
15
|
+
},
|
|
16
|
+
"rules": {
|
|
17
|
+
"no-trailing-spaces":[
|
|
18
|
+
"error",
|
|
19
|
+
{ "skipBlankLines": true }
|
|
20
|
+
],
|
|
21
|
+
"indent": [
|
|
22
|
+
"error",
|
|
23
|
+
2,
|
|
24
|
+
{ "SwitchCase":1 }
|
|
25
|
+
],
|
|
26
|
+
"linebreak-style": [
|
|
27
|
+
"error",
|
|
28
|
+
"windows"
|
|
29
|
+
],
|
|
30
|
+
"quotes": [
|
|
31
|
+
"error",
|
|
32
|
+
"single",
|
|
33
|
+
{ "avoidEscape": true }
|
|
34
|
+
],
|
|
35
|
+
"semi": [
|
|
36
|
+
"error",
|
|
37
|
+
"always"
|
|
38
|
+
],
|
|
39
|
+
"no-console": "off",
|
|
40
|
+
"no-unused-vars": [
|
|
41
|
+
"error",
|
|
42
|
+
{
|
|
43
|
+
"args": "none"
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
"no-cond-assign": [
|
|
47
|
+
"error",
|
|
48
|
+
"except-parens"
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
};
|
package/AppSrv.DB.js
CHANGED
|
@@ -60,7 +60,7 @@ exports.ExecScalar = function (context, sql, ptypes, params, callback, dbconfig,
|
|
|
60
60
|
|
|
61
61
|
exports.GetDBErrorMessage = function(dberrors, errmsg){
|
|
62
62
|
if(!dberrors) return null;
|
|
63
|
-
|
|
63
|
+
errmsg = (errmsg||'').toString().toLowerCase();
|
|
64
64
|
for (var i = 0; i < dberrors.length; i++) {
|
|
65
65
|
var dberr = dberrors[i];
|
|
66
66
|
var erex = dberr[0].toString().toLowerCase();
|
|
@@ -72,7 +72,7 @@ exports.GetDBErrorMessage = function(dberrors, errmsg){
|
|
|
72
72
|
else if (errmsg.indexOf(erex) >= 0) { return etxt; }
|
|
73
73
|
}
|
|
74
74
|
return null;
|
|
75
|
-
}
|
|
75
|
+
};
|
|
76
76
|
|
|
77
77
|
exports.AppDBError = function (req, res, err, stats, errorHandler) {
|
|
78
78
|
if(err.stats) stats = err.stats;
|
package/AppSrv.File.js
CHANGED
|
@@ -202,7 +202,7 @@ exports.Download = function (req, res, fullmodelid, keyid, fieldid, options) {
|
|
|
202
202
|
var datalockqueries = [];
|
|
203
203
|
var fields = _this.getFieldsByName(model.fields, fieldlist);
|
|
204
204
|
|
|
205
|
-
//Add DataLock parameters to SQL
|
|
205
|
+
//Add DataLock parameters to SQL
|
|
206
206
|
this.getDataLockSQL(req, model, model.fields, sql_ptypes, sql_params, verrors, function (datalockquery) { datalockqueries.push(datalockquery); });
|
|
207
207
|
//Add keys as SQL parameters
|
|
208
208
|
var keyfield = keys[0];
|
|
@@ -372,8 +372,6 @@ exports.ProcessFileOperations = function (keyval, fileops, rslt, stats, callback
|
|
|
372
372
|
if (fileop.src) filesrc = Helper.ReplaceAll(fileop.src, '%%%KEY%%%', keyval);
|
|
373
373
|
if (fileop.dest) filedest = Helper.ReplaceAll(fileop.dest, '%%%KEY%%%', keyval);
|
|
374
374
|
|
|
375
|
-
var allfiles = [];
|
|
376
|
-
|
|
377
375
|
async.waterfall([
|
|
378
376
|
function(filehandlercb){
|
|
379
377
|
//Get src file extension
|
package/AppSrv.Helper.js
CHANGED
|
@@ -24,7 +24,7 @@ module.exports = exports = {};
|
|
|
24
24
|
|
|
25
25
|
exports.getFieldNames = function (req, fields, perm, fcond) {
|
|
26
26
|
return _.map(exports.getFields(req, fields, perm, fcond), 'name');
|
|
27
|
-
}
|
|
27
|
+
};
|
|
28
28
|
|
|
29
29
|
exports.getFields = function (req, fields, perm, fcond) {
|
|
30
30
|
var rslt = [];
|
|
@@ -37,11 +37,11 @@ exports.getFields = function (req, fields, perm, fcond) {
|
|
|
37
37
|
}
|
|
38
38
|
});
|
|
39
39
|
return rslt;
|
|
40
|
-
}
|
|
40
|
+
};
|
|
41
41
|
|
|
42
42
|
exports.getFieldNamesWithProp = function (fields, prop) {
|
|
43
43
|
return _.map(exports.getFieldsWithProp(fields, prop), 'name');
|
|
44
|
-
}
|
|
44
|
+
};
|
|
45
45
|
|
|
46
46
|
exports.getFieldsWithProp = function (fields, prop) {
|
|
47
47
|
var rslt = [];
|
|
@@ -52,7 +52,7 @@ exports.getFieldsWithProp = function (fields, prop) {
|
|
|
52
52
|
}
|
|
53
53
|
});
|
|
54
54
|
return rslt;
|
|
55
|
-
}
|
|
55
|
+
};
|
|
56
56
|
|
|
57
57
|
exports.getFieldsByName = function (fields, fieldnames, fcond) {
|
|
58
58
|
var rslt = [];
|
|
@@ -62,7 +62,7 @@ exports.getFieldsByName = function (fields, fieldnames, fcond) {
|
|
|
62
62
|
var field = fields[i];
|
|
63
63
|
if (_.includes(fieldnames, field.name)){
|
|
64
64
|
for(var j=0;j<fieldnames_missing.length;j++){
|
|
65
|
-
if(fieldnames_missing[j]==field.name){
|
|
65
|
+
if(fieldnames_missing[j]==field.name){
|
|
66
66
|
fieldnames_missing.splice(j,1);
|
|
67
67
|
j--;
|
|
68
68
|
}
|
|
@@ -74,7 +74,7 @@ exports.getFieldsByName = function (fields, fieldnames, fcond) {
|
|
|
74
74
|
if(fieldnames_missing.length > 0){ this.jsh.Log.warning('Fields not found: ' + fieldnames_missing.join(', ')); }
|
|
75
75
|
|
|
76
76
|
return rslt;
|
|
77
|
-
}
|
|
77
|
+
};
|
|
78
78
|
|
|
79
79
|
//Static function
|
|
80
80
|
exports.getFieldByName = function (fields, fieldname) {
|
|
@@ -82,18 +82,18 @@ exports.getFieldByName = function (fields, fieldname) {
|
|
|
82
82
|
if (fields[i].name == fieldname) return fields[i];
|
|
83
83
|
}
|
|
84
84
|
return;
|
|
85
|
-
}
|
|
85
|
+
};
|
|
86
86
|
|
|
87
87
|
exports.getKeyNames = function (fields) {
|
|
88
88
|
return _.map(exports.getKeys(fields), 'name');
|
|
89
|
-
}
|
|
89
|
+
};
|
|
90
90
|
|
|
91
91
|
exports.getKeys = function (fields) {
|
|
92
92
|
return _.filter(fields, function (field) {
|
|
93
93
|
if (field.key) return true;
|
|
94
94
|
return false;
|
|
95
95
|
});
|
|
96
|
-
}
|
|
96
|
+
};
|
|
97
97
|
|
|
98
98
|
exports.getEncryptedFields = function (req, fields, perm) {
|
|
99
99
|
var rslt = [];
|
package/AppSrv.ModelExec.js
CHANGED
|
@@ -26,9 +26,6 @@ exports.getModelExec = function (req, res, fullmodelid, Q, P, form_m) {
|
|
|
26
26
|
var _this = this;
|
|
27
27
|
var model = this.jsh.getModel(req, fullmodelid);
|
|
28
28
|
if (!Helper.hasModelAction(req, model, 'B')) { Helper.GenError(req, res, -11, _this._tP('Invalid Model Access for @fullmodelid', { fullmodelid })); return; }
|
|
29
|
-
var fieldlist = this.getFieldNames(req, model.fields, 'B');
|
|
30
|
-
var filelist = this.getFileFieldNames(req, model.fields, 'B');
|
|
31
|
-
var keylist = this.getKeyNames(model.fields);
|
|
32
29
|
var crumbfieldlist = this.getFieldNames(req, model.fields, 'C');
|
|
33
30
|
|
|
34
31
|
if (!_this.ParamCheck('Q', Q, _.union(_.map(crumbfieldlist, function (field) { return '|' + field; }), ['|_action']), false)) {
|
|
@@ -36,7 +33,6 @@ exports.getModelExec = function (req, res, fullmodelid, Q, P, form_m) {
|
|
|
36
33
|
}
|
|
37
34
|
if (!_this.ParamCheck('P', P, [])) { Helper.GenError(req, res, -4, 'Invalid Parameters'); return; }
|
|
38
35
|
|
|
39
|
-
var nokey = (('nokey' in model) && (model.nokey));
|
|
40
36
|
var is_browse = (('_action' in Q) && (Q['_action'] == 'browse'));
|
|
41
37
|
|
|
42
38
|
//Return applicable drop-down lists
|
|
@@ -53,12 +49,12 @@ exports.getModelExec = function (req, res, fullmodelid, Q, P, form_m) {
|
|
|
53
49
|
if(_this.addLOVTasks(req, res, model, Q, dbtasks)===false) return;
|
|
54
50
|
if (!_.isEmpty(verrors)) { Helper.GenError(req, res, -2, verrors[''].join('\n')); return; }
|
|
55
51
|
return dbtasks;
|
|
56
|
-
}
|
|
52
|
+
};
|
|
57
53
|
|
|
58
54
|
exports.postModelExec = function (req, res, fullmodelid, Q, P, onComplete) {
|
|
59
55
|
var _this = this;
|
|
60
56
|
var jsh = this.jsh;
|
|
61
|
-
if (!jsh.hasModel(req, fullmodelid)) throw new Error(
|
|
57
|
+
if (!jsh.hasModel(req, fullmodelid)) throw new Error('Error: Model ' + fullmodelid + ' not found in collection.');
|
|
62
58
|
var model = jsh.getModel(req, fullmodelid);
|
|
63
59
|
if (!Helper.hasModelAction(req, model, 'U')) { Helper.GenError(req, res, -11, _this._tP('Invalid Model Access for @fullmodelid', { fullmodelid })); return; }
|
|
64
60
|
var db = jsh.getModelDB(req, fullmodelid);
|
|
@@ -69,14 +65,14 @@ exports.postModelExec = function (req, res, fullmodelid, Q, P, onComplete) {
|
|
|
69
65
|
if (!_this.ParamCheck('Q', Q, [])) { Helper.GenError(req, res, -4, 'Invalid Parameters'); return; }
|
|
70
66
|
if (!_this.ParamCheck('P', P, Pcheck)) { Helper.GenError(req, res, -4, 'Invalid Parameters'); return; }
|
|
71
67
|
|
|
72
|
-
if (!('sqlexec' in model)) throw new Error(
|
|
68
|
+
if (!('sqlexec' in model)) throw new Error('Error: Model ' + fullmodelid + ' missing sqlexec.');
|
|
73
69
|
var sql_ptypes = [];
|
|
74
70
|
var sql_params = {};
|
|
75
71
|
var verrors = {};
|
|
76
72
|
var param_datalocks = [];
|
|
77
73
|
var datalockqueries = [];
|
|
78
74
|
|
|
79
|
-
//Add fields from post
|
|
75
|
+
//Add fields from post
|
|
80
76
|
var fields = _this.getFieldsByName(model.fields, fieldlist);
|
|
81
77
|
_.each(fields, function (field) {
|
|
82
78
|
var fname = field.name;
|
|
@@ -96,7 +92,7 @@ exports.postModelExec = function (req, res, fullmodelid, Q, P, onComplete) {
|
|
|
96
92
|
else throw new Error('Missing parameter ' + fname);
|
|
97
93
|
});
|
|
98
94
|
|
|
99
|
-
//Add DataLock parameters to SQL
|
|
95
|
+
//Add DataLock parameters to SQL
|
|
100
96
|
_this.getDataLockSQL(req, model, model.fields, sql_ptypes, sql_params, verrors, function (datalockquery) { datalockqueries.push(datalockquery); });
|
|
101
97
|
|
|
102
98
|
verrors = _.merge(verrors, model.xvalidate.Validate('UK', sql_params));
|
|
@@ -116,6 +112,6 @@ exports.postModelExec = function (req, res, fullmodelid, Q, P, onComplete) {
|
|
|
116
112
|
});
|
|
117
113
|
};
|
|
118
114
|
return onComplete(null, dbtasks);
|
|
119
|
-
}
|
|
115
|
+
};
|
|
120
116
|
|
|
121
117
|
return module.exports;
|
package/AppSrv.ModelForm.js
CHANGED
|
@@ -42,6 +42,7 @@ exports.getModelForm = function (req, res, fullmodelid, Q, P, form_m) {
|
|
|
42
42
|
if ((encryptedfields.length > 0) && !(req.secure) && (!_this.jsh.Config.system_settings.allow_insecure_http_encryption)) { Helper.GenError(req, res, -51, 'Encrypted fields require HTTPS connection'); return; }
|
|
43
43
|
|
|
44
44
|
|
|
45
|
+
|
|
45
46
|
var is_insert = false;
|
|
46
47
|
var is_browse = false;
|
|
47
48
|
var selecttype = 'single';
|
|
@@ -54,11 +55,11 @@ exports.getModelForm = function (req, res, fullmodelid, Q, P, form_m) {
|
|
|
54
55
|
else if (_this.ParamCheck('Q', Q, _.union(_.map(foreignkeylist, function (field) { return '|' + field; }), ['|_action']), false)) {
|
|
55
56
|
selecttype = 'multiple';
|
|
56
57
|
}
|
|
57
|
-
else {
|
|
58
|
+
else {
|
|
58
59
|
//Display missing keys
|
|
59
60
|
_this.ParamCheck('Q', Q, _.map(keylist, function (key) { return '&' + key; }), true);
|
|
60
61
|
Helper.GenError(req, res, -4, 'Invalid Parameters');
|
|
61
|
-
return;
|
|
62
|
+
return;
|
|
62
63
|
}
|
|
63
64
|
}
|
|
64
65
|
else {
|
|
@@ -124,7 +125,7 @@ exports.getModelForm = function (req, res, fullmodelid, Q, P, form_m) {
|
|
|
124
125
|
var keys = [];
|
|
125
126
|
if (is_insert && !Helper.hasModelAction(req, model, 'I')) { Helper.GenError(req, res, -11, _this._tP('Invalid Model Access for @fullmodelid', { fullmodelid })); return; }
|
|
126
127
|
if (!is_insert && !nokey && !model.unbound) {
|
|
127
|
-
//Add dynamic parameters from query string
|
|
128
|
+
//Add dynamic parameters from query string
|
|
128
129
|
if (selecttype == 'single') keys = this.getKeys(model.fields);
|
|
129
130
|
else if (selecttype == 'multiple') keys = this.getFields(req, model.fields, 'F');
|
|
130
131
|
for (var i = 0; i < keys.length; i++) {
|
|
@@ -205,7 +206,7 @@ exports.getModelForm = function (req, res, fullmodelid, Q, P, form_m) {
|
|
|
205
206
|
}
|
|
206
207
|
callback(err, rslt, stats);
|
|
207
208
|
});
|
|
208
|
-
}
|
|
209
|
+
};
|
|
209
210
|
else if (is_insert && (selecttype == 'multiple')) {
|
|
210
211
|
dbtasks[0][fullmodelid] = function (dbtrans, callback) {
|
|
211
212
|
var rslt = [];
|
|
@@ -232,7 +233,7 @@ exports.getModelForm = function (req, res, fullmodelid, Q, P, form_m) {
|
|
|
232
233
|
if(_this.addLOVTasks(req, res, model, Q, dbtasks[1], { action: targetperm })===false) return;
|
|
233
234
|
if (!_.isEmpty(verrors)) { Helper.GenError(req, res, -2, verrors[''].join('\n')); return; }
|
|
234
235
|
return dbtasks;
|
|
235
|
-
}
|
|
236
|
+
};
|
|
236
237
|
|
|
237
238
|
exports.putModelForm = function (req, res, fullmodelid, Q, P, onComplete) {
|
|
238
239
|
var _this = this;
|
|
@@ -303,7 +304,7 @@ exports.putModelForm = function (req, res, fullmodelid, Q, P, onComplete) {
|
|
|
303
304
|
}
|
|
304
305
|
else throw new Error('Missing parameter ' + fname);
|
|
305
306
|
});
|
|
306
|
-
//Add DataLock parameters to Encryption SQL
|
|
307
|
+
//Add DataLock parameters to Encryption SQL
|
|
307
308
|
_this.getDataLockSQL(req, model, model.fields, enc_sql_ptypes, enc_sql_params, verrors, function (datalockquery) { enc_datalockqueries.push(datalockquery); });
|
|
308
309
|
}
|
|
309
310
|
|
|
@@ -330,7 +331,7 @@ exports.putModelForm = function (req, res, fullmodelid, Q, P, onComplete) {
|
|
|
330
331
|
else throw new Error('Missing parameter ' + fname);
|
|
331
332
|
});
|
|
332
333
|
|
|
333
|
-
var ignore_subs = _.map(subs, function(val){ return '_obj.'+val });
|
|
334
|
+
var ignore_subs = _.map(subs, function(val){ return '_obj.'+val; });
|
|
334
335
|
verrors = _.merge(verrors, model.xvalidate.Validate('I', _.merge(vfiles, enc_sql_params, sql_params), '', ignore_subs));
|
|
335
336
|
if (!_.isEmpty(verrors)) { Helper.GenError(req, res, -2, verrors[''].join('\n')); return; }
|
|
336
337
|
|
|
@@ -392,14 +393,14 @@ exports.putModelForm = function (req, res, fullmodelid, Q, P, onComplete) {
|
|
|
392
393
|
}
|
|
393
394
|
if (fileops.length > 0) dbtasks['_POSTPROCESS'] = function (callback) {
|
|
394
395
|
_this.ProcessFileOperationsDone(fileops, callback);
|
|
395
|
-
}
|
|
396
|
+
};
|
|
396
397
|
return onComplete(null, dbtasks);
|
|
397
398
|
});
|
|
398
|
-
}
|
|
399
|
+
};
|
|
399
400
|
|
|
400
401
|
exports.postModelForm = function (req, res, fullmodelid, Q, P, onComplete) {
|
|
401
402
|
var _this = this;
|
|
402
|
-
if (!this.jsh.hasModel(req, fullmodelid)) throw new Error(
|
|
403
|
+
if (!this.jsh.hasModel(req, fullmodelid)) throw new Error('Error: Model ' + fullmodelid + ' not found in collection.');
|
|
403
404
|
var model = this.jsh.getModel(req, fullmodelid);
|
|
404
405
|
if (!Helper.hasModelAction(req, model, 'U')) { Helper.GenError(req, res, -11, _this._tP('Invalid Model Access for @fullmodelid', { fullmodelid })); return; }
|
|
405
406
|
|
|
@@ -434,14 +435,14 @@ exports.postModelForm = function (req, res, fullmodelid, Q, P, onComplete) {
|
|
|
434
435
|
_.each(encryptedfields, function (field) {
|
|
435
436
|
if (field.type == 'encascii') {
|
|
436
437
|
if ('hash' in field) {
|
|
437
|
-
|
|
438
|
+
let hashfield = _.find(model.fields, function (xfield) { return xfield.name == field.hash; });
|
|
438
439
|
if (typeof hashfield == 'undefined') throw new Error('Field ' + field.name + ' hash is not defined.');
|
|
439
440
|
hashfields[field.name] = hashfield;
|
|
440
441
|
}
|
|
441
442
|
}
|
|
442
443
|
});
|
|
443
444
|
|
|
444
|
-
//Add key from query string
|
|
445
|
+
//Add key from query string
|
|
445
446
|
var keys = _this.getKeys(model.fields);
|
|
446
447
|
_.each(keys, function (field) {
|
|
447
448
|
var fname = field.name;
|
|
@@ -485,7 +486,7 @@ exports.postModelForm = function (req, res, fullmodelid, Q, P, onComplete) {
|
|
|
485
486
|
else throw new Error('Missing parameter ' + fname);
|
|
486
487
|
});
|
|
487
488
|
|
|
488
|
-
//Add DataLock parameters to SQL
|
|
489
|
+
//Add DataLock parameters to SQL
|
|
489
490
|
_this.getDataLockSQL(req, model, model.fields, sql_ptypes, sql_params, verrors, function (datalockquery) { datalockqueries.push(datalockquery); });
|
|
490
491
|
|
|
491
492
|
verrors = _.merge(verrors, model.xvalidate.Validate('UK', _.merge(vfiles, sql_params), '', vignorefiles, req._roles));
|
|
@@ -501,7 +502,7 @@ exports.postModelForm = function (req, res, fullmodelid, Q, P, onComplete) {
|
|
|
501
502
|
if (clearval.length == 0) {
|
|
502
503
|
sql_params[field.name] = null;
|
|
503
504
|
if ('hash' in field) {
|
|
504
|
-
|
|
505
|
+
let hashfield = hashfields[field.name];
|
|
505
506
|
sql_ptypes.push(_this.getDBType(hashfield));
|
|
506
507
|
sql_params[hashfield.name] = null;
|
|
507
508
|
}
|
|
@@ -513,10 +514,10 @@ exports.postModelForm = function (req, res, fullmodelid, Q, P, onComplete) {
|
|
|
513
514
|
cipher.update(clearval, 'ascii');
|
|
514
515
|
sql_params[field.name] = cipher.final();
|
|
515
516
|
if ('hash' in field) {
|
|
516
|
-
|
|
517
|
+
let hashfield = hashfields[field.name];
|
|
517
518
|
if (!(hashfield.salt in _this.jsh.Config.salts)) throw new Error('Hash salt not defined.');
|
|
518
519
|
sql_ptypes.push(_this.getDBType(hashfield));
|
|
519
|
-
sql_params[hashfield.name] = crypto.createHash('sha1').update(clearval + _this.jsh.Config.salts[hashfield.salt]).digest()
|
|
520
|
+
sql_params[hashfield.name] = crypto.createHash('sha1').update(clearval + _this.jsh.Config.salts[hashfield.salt]).digest();
|
|
520
521
|
}
|
|
521
522
|
}
|
|
522
523
|
}
|
|
@@ -557,14 +558,14 @@ exports.postModelForm = function (req, res, fullmodelid, Q, P, onComplete) {
|
|
|
557
558
|
|
|
558
559
|
if (fileops.length > 0) dbtasks['_POSTPROCESS'] = function (callback) {
|
|
559
560
|
_this.ProcessFileOperationsDone(fileops, callback);
|
|
560
|
-
}
|
|
561
|
+
};
|
|
561
562
|
|
|
562
563
|
return onComplete(null, dbtasks);
|
|
563
564
|
});
|
|
564
|
-
}
|
|
565
|
+
};
|
|
565
566
|
|
|
566
567
|
exports.deleteModelForm = function (req, res, fullmodelid, Q, P, onComplete) {
|
|
567
|
-
if (!this.jsh.hasModel(req, fullmodelid)) throw new Error(
|
|
568
|
+
if (!this.jsh.hasModel(req, fullmodelid)) throw new Error('Error: Model ' + fullmodelid + ' not found in collection.');
|
|
568
569
|
var _this = this;
|
|
569
570
|
var model = this.jsh.getModel(req, fullmodelid);
|
|
570
571
|
if (!Helper.hasModelAction(req, model, 'D')) { Helper.GenError(req, res, -11, _this._tP('Invalid Model Access for @fullmodelid', { fullmodelid })); return; }
|
|
@@ -595,7 +596,7 @@ exports.deleteModelForm = function (req, res, fullmodelid, Q, P, onComplete) {
|
|
|
595
596
|
else throw new Error('Missing parameter ' + fname);
|
|
596
597
|
});
|
|
597
598
|
|
|
598
|
-
//Add DataLock parameters to SQL
|
|
599
|
+
//Add DataLock parameters to SQL
|
|
599
600
|
_this.getDataLockSQL(req, model, model.fields, sql_ptypes, sql_params, verrors, function (datalockquery) { datalockqueries.push(datalockquery); });
|
|
600
601
|
|
|
601
602
|
verrors = _.merge(verrors, model.xvalidate.Validate('K', sql_params));
|
|
@@ -614,9 +615,10 @@ exports.deleteModelForm = function (req, res, fullmodelid, Q, P, onComplete) {
|
|
|
614
615
|
};
|
|
615
616
|
//Add post-processing task to delete any files
|
|
616
617
|
if (filelist.length > 0) {
|
|
618
|
+
var keyval = '';
|
|
617
619
|
if (keys.length == 1) keyval = sql_params[keys[0].name];
|
|
618
620
|
else throw new Error('File uploads require one key');
|
|
619
|
-
if ((typeof keyval == 'undefined') || !keyval) return
|
|
621
|
+
if ((typeof keyval == 'undefined') || !keyval) return Helper.GenError(req, res, -13, 'Invalid file key');
|
|
620
622
|
|
|
621
623
|
var fileops = [];
|
|
622
624
|
_.each(filelist, function (file) {
|
|
@@ -630,9 +632,9 @@ exports.deleteModelForm = function (req, res, fullmodelid, Q, P, onComplete) {
|
|
|
630
632
|
});
|
|
631
633
|
dbtasks['_POSTPROCESS'] = function (callback) {
|
|
632
634
|
_this.ProcessFileOperationsDone(fileops, callback);
|
|
633
|
-
}
|
|
635
|
+
};
|
|
634
636
|
}
|
|
635
637
|
return onComplete(null, dbtasks);
|
|
636
|
-
}
|
|
638
|
+
};
|
|
637
639
|
|
|
638
640
|
return module.exports;
|
package/AppSrv.ModelGrid.js
CHANGED
|
@@ -40,7 +40,7 @@ exports.getModelRecordset = function (req, res, fullmodelid, Q, P, rowlimit, opt
|
|
|
40
40
|
searchlist = _.union(keylist, searchlist);
|
|
41
41
|
var encryptedfields = this.getFields(req, model.fields, '*', function(field){ return field.type=='encascii'; });
|
|
42
42
|
if (encryptedfields.length > 0) throw new Error('Encrypted fields not supported on GRID (field.type=encascii)');
|
|
43
|
-
|
|
43
|
+
encryptedfields = this.getEncryptedFields(req, model.fields, 'S'); //Encrypted fields can be used for search
|
|
44
44
|
if ((encryptedfields.length > 0) && !(req.secure) && (!_this.jsh.Config.system_settings.allow_insecure_http_encryption)) { Helper.GenError(req, res, -51, 'Encrypted / hash fields require HTTPS connection'); return; }
|
|
45
45
|
var db = _this.jsh.getModelDB(req, fullmodelid);
|
|
46
46
|
if ('d' in Q) P = JSON.parse(Q.d);
|
|
@@ -80,7 +80,7 @@ exports.getModelRecordset = function (req, res, fullmodelid, Q, P, rowlimit, opt
|
|
|
80
80
|
var sortfield = val.substring(1);
|
|
81
81
|
var lovtxtfield = '';
|
|
82
82
|
if(sortfield.indexOf('__'+_this.jsh.map.code_txt+'__')==0){
|
|
83
|
-
|
|
83
|
+
lovtxtfield = sortfield;
|
|
84
84
|
sortfield = sortfield.substr(_this.jsh.map.code_txt.length + 4);
|
|
85
85
|
}
|
|
86
86
|
var sortdir = val[0];
|
|
@@ -89,7 +89,7 @@ exports.getModelRecordset = function (req, res, fullmodelid, Q, P, rowlimit, opt
|
|
|
89
89
|
else throw new Error('Invalid sort string');
|
|
90
90
|
if (!_.includes(availablesortfieldslist, sortfield)) throw new Error('Invalid sort field ' + sortfield);
|
|
91
91
|
|
|
92
|
-
|
|
92
|
+
let field = _this.getFieldByName(model.fields, sortfield);
|
|
93
93
|
var sortfieldname = sortfield;
|
|
94
94
|
if(lovtxtfield && field.lov && !field.lov.showcode) sortfieldname = lovtxtfield;
|
|
95
95
|
sortfields.push({ 'field': sortfieldname, 'dir': sortdir, 'sql': (field.sqlsort || '') });
|
|
@@ -105,7 +105,7 @@ exports.getModelRecordset = function (req, res, fullmodelid, Q, P, rowlimit, opt
|
|
|
105
105
|
var search_items = JSON.parse(Q.searchjson);
|
|
106
106
|
var search_join = 'and';
|
|
107
107
|
if (_.isArray(search_items) && (search_items.length > 0)) {
|
|
108
|
-
for (
|
|
108
|
+
for (let i = 0; i < search_items.length; i++) {
|
|
109
109
|
var search_column = search_items[i].Column;
|
|
110
110
|
var search_value = search_items[i].Value;
|
|
111
111
|
var search_comparison = 'contains';
|
|
@@ -129,7 +129,6 @@ exports.getModelRecordset = function (req, res, fullmodelid, Q, P, rowlimit, opt
|
|
|
129
129
|
if (search_column == 'ALL') {
|
|
130
130
|
if (searchlist.length == 0) continue;
|
|
131
131
|
var searchall = [];
|
|
132
|
-
var firstSearchItem = true;
|
|
133
132
|
var searchlistfields = this.getFieldsByName(model.fields, searchlist);
|
|
134
133
|
_.each(searchlistfields, function (field) {
|
|
135
134
|
if(field.disable_search_all) return;
|
|
@@ -146,7 +145,7 @@ exports.getModelRecordset = function (req, res, fullmodelid, Q, P, rowlimit, opt
|
|
|
146
145
|
}
|
|
147
146
|
}
|
|
148
147
|
else {
|
|
149
|
-
|
|
148
|
+
let field = this.getFieldByName(model.fields, search_column);
|
|
150
149
|
var searchtermsql = this.addSearchTerm(req, model, field, i, search_value, search_comparison, sql_ptypes, sql_params, verrors);
|
|
151
150
|
if (searchtermsql) {
|
|
152
151
|
if (searchparams.length) searchparams.push(search_join);
|
|
@@ -177,8 +176,8 @@ exports.getModelRecordset = function (req, res, fullmodelid, Q, P, rowlimit, opt
|
|
|
177
176
|
}
|
|
178
177
|
|
|
179
178
|
var keys = searchfields;
|
|
180
|
-
for (
|
|
181
|
-
|
|
179
|
+
for (let i = 0; i < keys.length; i++) {
|
|
180
|
+
let field = keys[i];
|
|
182
181
|
var fname = field.name;
|
|
183
182
|
if ((fname in P) && !(fname in sql_params)) {
|
|
184
183
|
var dbtype = _this.getDBType(field);
|
|
@@ -186,15 +185,15 @@ exports.getModelRecordset = function (req, res, fullmodelid, Q, P, rowlimit, opt
|
|
|
186
185
|
sql_params[fname] = _this.DeformatParam(field, P[fname], verrors);
|
|
187
186
|
}
|
|
188
187
|
}
|
|
189
|
-
for (
|
|
190
|
-
|
|
188
|
+
for (let i = 0; i < model.fields.length; i++){
|
|
189
|
+
let field = model.fields[i];
|
|
191
190
|
if(field.lov && field.lov.sqlselect && field.lov.sqlselect_params){
|
|
192
191
|
for(var j = 0; j < field.lov.sqlselect_params.length; j++){
|
|
193
192
|
if(!(field.lov.sqlselect_params[j] in P)){ Helper.GenError(req, res, -99999, model.id + ' > ' + field.name + ': Missing lov.sqlselect parameter @'+field.lov.sqlselect_params[j] + ' - grid parameters must be passed in the querystring or bindings. The lov.sqlselect is inserted into the grid select statement; if this is a per-record lookup, use the expression LOVSQLTABLE.FIELD = MODELTABLE.FIELD'); return; }
|
|
194
193
|
}
|
|
195
194
|
}
|
|
196
195
|
}
|
|
197
|
-
//Add DataLock parameters to SQL
|
|
196
|
+
//Add DataLock parameters to SQL
|
|
198
197
|
this.getDataLockSQL(req, model, model.fields, sql_ptypes, sql_params, verrors, function (datalockquery) { datalockqueries.push(datalockquery); }, null, fullmodelid);
|
|
199
198
|
verrors = _.merge(verrors, model.xvalidate.Validate('BFK', sql_params, undefined, undefined, undefined, { ignoreUndefined: true }));
|
|
200
199
|
if (!_.isEmpty(verrors)) { Helper.GenError(req, res, -2, verrors[''].join('\n')); return; }
|
|
@@ -283,7 +282,7 @@ exports.getModelRecordset = function (req, res, fullmodelid, Q, P, rowlimit, opt
|
|
|
283
282
|
if(_this.addTitleTasks(req, res, model, P, dbtasks, (is_browse?'B':'U'))===false) return;
|
|
284
283
|
}
|
|
285
284
|
return dbtasks;
|
|
286
|
-
}
|
|
285
|
+
};
|
|
287
286
|
|
|
288
287
|
exports.exportCSV = function (req, res, dbtasks, fullmodelid, options) {
|
|
289
288
|
var _this = this;
|
|
@@ -315,17 +314,17 @@ exports.exportCSV = function (req, res, dbtasks, fullmodelid, options) {
|
|
|
315
314
|
dbtasks = _.reduce(dbtasks, function (rslt, dbtask, key) { rslt[key] = async.apply(dbtask, undefined); return rslt; }, {});
|
|
316
315
|
db.ExecTasks(dbtasks, function (err, rslt, stats) {
|
|
317
316
|
if (err != null) { _this.AppDBError(req, res, err, stats); return; }
|
|
318
|
-
if (!fullmodelid in rslt) throw new Error('DB result missing model.');
|
|
317
|
+
if (!(fullmodelid in rslt)) throw new Error('DB result missing model.');
|
|
319
318
|
var eof = false;
|
|
320
319
|
if (_.isArray(rslt[fullmodelid]) && (_.isObject(rslt[fullmodelid][rslt[fullmodelid].length - 1])) && ('_eof' in rslt[fullmodelid][rslt[fullmodelid].length - 1])) {
|
|
321
|
-
var
|
|
322
|
-
eof =
|
|
320
|
+
var rslt_eof = rslt[fullmodelid].pop();
|
|
321
|
+
eof = rslt_eof._eof;
|
|
323
322
|
}
|
|
324
323
|
//Add header
|
|
325
324
|
if (rslt[fullmodelid].length > 0) {
|
|
326
325
|
var header = {};
|
|
327
326
|
var frow = _.extend({}, rslt[fullmodelid][0]);
|
|
328
|
-
for (
|
|
327
|
+
for (let fcol in frow) {
|
|
329
328
|
//Ignore columns that should not be exported
|
|
330
329
|
if(!_.includes(exportColumns, fcol)){ delete frow[fcol]; continue; }
|
|
331
330
|
var field = _this.getFieldByName(model.fields, fcol);
|
|
@@ -342,10 +341,10 @@ exports.exportCSV = function (req, res, dbtasks, fullmodelid, options) {
|
|
|
342
341
|
//If data was truncated, add notification row
|
|
343
342
|
if (!eof) {
|
|
344
343
|
var eofrow = {};
|
|
345
|
-
for (
|
|
344
|
+
for (let fcol in frow) {
|
|
346
345
|
eofrow[fcol] = '';
|
|
347
346
|
}
|
|
348
|
-
for (
|
|
347
|
+
for (let fcol in frow) {
|
|
349
348
|
eofrow[fcol] = 'Data exceeded limit of ' + _this.jsh.Config.export_rowlimit + ' rows, data has been truncated.';
|
|
350
349
|
break;
|
|
351
350
|
}
|
|
@@ -355,7 +354,7 @@ exports.exportCSV = function (req, res, dbtasks, fullmodelid, options) {
|
|
|
355
354
|
//Process data
|
|
356
355
|
for (var i = dataidx; i < rslt[fullmodelid].length; i++) {
|
|
357
356
|
var crow = rslt[fullmodelid][i];
|
|
358
|
-
for (ccol in crow) {
|
|
357
|
+
for (let ccol in crow) {
|
|
359
358
|
if(!ccol) continue;
|
|
360
359
|
//Overwrite code_val with code_txt
|
|
361
360
|
if(Helper.beginsWith(ccol, '__'+jsh.map.code_txt+'__')){
|
|
@@ -367,7 +366,7 @@ exports.exportCSV = function (req, res, dbtasks, fullmodelid, options) {
|
|
|
367
366
|
crow[ccol] = crow[ccol].toISOString();//.replace('T', ' ').replace('Z', '');
|
|
368
367
|
}
|
|
369
368
|
}
|
|
370
|
-
for (ccol in crow) {
|
|
369
|
+
for (let ccol in crow) {
|
|
371
370
|
if(!_.includes(exportColumns, ccol)){ delete crow[ccol]; continue; }
|
|
372
371
|
}
|
|
373
372
|
}
|
|
@@ -380,6 +379,6 @@ exports.exportCSV = function (req, res, dbtasks, fullmodelid, options) {
|
|
|
380
379
|
});
|
|
381
380
|
csv.stringify(rslt[fullmodelid], { quotedString: true }).pipe(res);
|
|
382
381
|
});
|
|
383
|
-
}
|
|
382
|
+
};
|
|
384
383
|
|
|
385
384
|
return module.exports;
|