hola-server 0.6.4 → 0.6.6
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/core/bash.js +283 -0
- package/core/chart.js +36 -0
- package/core/cron.js +10 -0
- package/core/lhs.js +27 -0
- package/core/meta.js +16 -1
- package/core/msg.js +11 -0
- package/http/session.js +38 -2
- package/index.js +6 -1
- package/package.json +4 -2
- package/router/clone.js +10 -2
- package/router/create.js +10 -2
- package/router/delete.js +10 -1
- package/router/read.js +45 -3
- package/router/update.js +10 -1
- package/setting.js +21 -1
package/core/bash.js
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
const { exec } = require("child_process");
|
|
2
|
+
const { is_log_debug, is_log_error, log_debug, log_error } = require('../db/db');
|
|
3
|
+
|
|
4
|
+
const LOG_BASH = "bash";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Run script and get stdout
|
|
8
|
+
* @param {host info,contains user,ip and password} host
|
|
9
|
+
* @param {commands to run} script
|
|
10
|
+
* @returns
|
|
11
|
+
*/
|
|
12
|
+
const run_script = async (host, script) => {
|
|
13
|
+
return new Promise((resolve) => {
|
|
14
|
+
exec(`sshpass -p '${host.pwd}' ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -p ${host.port} ${host.user}@${host.ip} /bin/bash <<'EOT' \n ${script} \nEOT\n`, { maxBuffer: 1024 * 150000 }, (error, stdout) => {
|
|
15
|
+
if (error) {
|
|
16
|
+
if (is_log_error()) {
|
|
17
|
+
log_error(LOG_BASH, "error running on host:" + host.name + " the script:" + script + ",error:" + error);
|
|
18
|
+
}
|
|
19
|
+
resolve({ err: "error running the script:" + script + ",error:" + error });
|
|
20
|
+
} else {
|
|
21
|
+
if (is_log_debug()) {
|
|
22
|
+
log_debug(LOG_BASH, "executing on host:" + host.name + ", script:" + script + ",stdout:" + stdout);
|
|
23
|
+
}
|
|
24
|
+
resolve({ stdout: stdout });
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const run_script_file = async (host, script_file) => {
|
|
31
|
+
return new Promise((resolve) => {
|
|
32
|
+
exec(`sshpass -p '${host.pwd}' ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -p ${host.port} ${host.user}@${host.ip} /bin/bash < ${script_file}`, (error, stdout) => {
|
|
33
|
+
if (error) {
|
|
34
|
+
if (is_log_error()) {
|
|
35
|
+
log_error(LOG_BASH, "error running on host:" + host.name + " the script_file:" + script_file + ",error:" + error);
|
|
36
|
+
}
|
|
37
|
+
resolve({ err: "error running the script:" + script_file + ",error:" + error });
|
|
38
|
+
} else {
|
|
39
|
+
if (is_log_debug()) {
|
|
40
|
+
log_debug(LOG_BASH, "executing on host:" + host.name + ", script_file:" + script_file + ",stdout:" + stdout);
|
|
41
|
+
}
|
|
42
|
+
resolve({ stdout: stdout });
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Run command in local host
|
|
50
|
+
* @param {command to execute} cmd
|
|
51
|
+
* @returns
|
|
52
|
+
*/
|
|
53
|
+
const run_local_cmd = async (cmd, log_extra) => {
|
|
54
|
+
return new Promise((resolve) => {
|
|
55
|
+
exec(cmd, { maxBuffer: 1024 * 15000000 }, (error, stdout) => {
|
|
56
|
+
if (error) {
|
|
57
|
+
if (is_log_error()) {
|
|
58
|
+
log_error(LOG_BASH, "error running on local host with cmd:" + cmd + ",error:" + error, log_extra);
|
|
59
|
+
}
|
|
60
|
+
resolve({ err: "error running the cmd:" + cmd + ",error:" + error }, log_extra);
|
|
61
|
+
} else {
|
|
62
|
+
if (is_log_debug()) {
|
|
63
|
+
log_debug(LOG_BASH, "executing on local host with cmd:" + cmd + ",stdout:" + stdout, log_extra);
|
|
64
|
+
}
|
|
65
|
+
resolve({ stdout: stdout });
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Scp remote file to local file
|
|
73
|
+
* @param {remote host} host
|
|
74
|
+
* @param {remote file path} remote_file
|
|
75
|
+
* @param {local file path} locale_file
|
|
76
|
+
* @returns
|
|
77
|
+
*/
|
|
78
|
+
const scp = async (host, remote_file, local_file) => {
|
|
79
|
+
return new Promise((resolve) => {
|
|
80
|
+
exec(`sshpass -p '${host.pwd}' scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -P ${host.port} -q ${host.user}@${host.ip}:${remote_file} ${local_file}`, (error, stdout) => {
|
|
81
|
+
if (error) {
|
|
82
|
+
if (is_log_error()) {
|
|
83
|
+
log_error(LOG_BASH, "error scp on host:" + host.name + " remote:" + remote_file + ",local:" + local_file + ",error:" + error);
|
|
84
|
+
}
|
|
85
|
+
resolve({ err: "error scp:" + remote_file + " to locale:" + local_file + ",err:" + error });
|
|
86
|
+
} else {
|
|
87
|
+
if (is_log_debug()) {
|
|
88
|
+
log_debug(LOG_BASH, "executing scp on host:" + host.name + ", remote:" + remote_file + ",local:" + local_file + ",stdout:" + stdout);
|
|
89
|
+
}
|
|
90
|
+
resolve({ stdout: stdout });
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
*Just run simple command and get result directly
|
|
98
|
+
* @param {host info,contains user,ip and password} host
|
|
99
|
+
* @param {command to run} cmd
|
|
100
|
+
* @returns
|
|
101
|
+
*/
|
|
102
|
+
const run_simple_cmd = async (host, cmd) => {
|
|
103
|
+
const { err, stdout } = await run_script(host, cmd);
|
|
104
|
+
if (err) {
|
|
105
|
+
return null;
|
|
106
|
+
} else {
|
|
107
|
+
return stdout.trim();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
*Just run simple command and get result directly
|
|
113
|
+
* @param {command to run} cmd
|
|
114
|
+
* @returns
|
|
115
|
+
*/
|
|
116
|
+
const run_simple_local_cmd = async (cmd) => {
|
|
117
|
+
const { err, stdout } = await run_local_cmd(cmd);
|
|
118
|
+
if (err) {
|
|
119
|
+
return null;
|
|
120
|
+
} else {
|
|
121
|
+
return stdout.trim();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Use regular expression to match the pattern to get some part of value
|
|
127
|
+
Speed: Unknown
|
|
128
|
+
Manufacturer: NO DIMM
|
|
129
|
+
Serial Number: NO DIMM
|
|
130
|
+
Asset Tag:
|
|
131
|
+
Part Number: NO DIMM
|
|
132
|
+
Rank: Unknown
|
|
133
|
+
Configured Memory Speed: Unknown
|
|
134
|
+
Minimum Voltage: 1.2 V
|
|
135
|
+
Maximum Voltage: 1.2 V
|
|
136
|
+
Configured Voltage: 1.2 V
|
|
137
|
+
|
|
138
|
+
* @param {stdout of the run_cmd} stdout
|
|
139
|
+
* @param {key to retrieve info} key
|
|
140
|
+
* @returns
|
|
141
|
+
*/
|
|
142
|
+
const get_info = (stdout, key) => {
|
|
143
|
+
const word_key = key.split(" ").join("\\s+");
|
|
144
|
+
const regex = new RegExp(`\n\\s?${word_key}\\s?:(.*)\\s`, 'g');
|
|
145
|
+
if (is_log_debug()) {
|
|
146
|
+
log_debug(LOG_BASH, "get_info and regex:" + JSON.stringify(regex));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const results = stdout.matchAll(regex);
|
|
150
|
+
|
|
151
|
+
const matched = [];
|
|
152
|
+
for (let result of results) {
|
|
153
|
+
matched.push(result[1].trim());
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (is_log_debug()) {
|
|
157
|
+
log_debug(LOG_BASH, "get_info and matched:" + JSON.stringify(matched));
|
|
158
|
+
}
|
|
159
|
+
return matched;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Get the lines of array
|
|
164
|
+
* @param {array of lines} array
|
|
165
|
+
* @param {array of line number to get,use range to define the lines} lines
|
|
166
|
+
* @returns
|
|
167
|
+
*/
|
|
168
|
+
const get_lines = (array, lines) => {
|
|
169
|
+
const result = [];
|
|
170
|
+
lines.forEach(line => {
|
|
171
|
+
result.push(array[line]);
|
|
172
|
+
});
|
|
173
|
+
return result;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Read all the lines to object such as lscpu to retrieve all the cpu info
|
|
178
|
+
Core(s) per socket: 28
|
|
179
|
+
Socket(s): 2
|
|
180
|
+
NUMA node(s): 2
|
|
181
|
+
Vendor ID: GenuineIntel
|
|
182
|
+
CPU family: 6
|
|
183
|
+
Model: 85
|
|
184
|
+
Model name: Intel(R) Xeon(R) Gold 6258R CPU @ 2.70GHz
|
|
185
|
+
Stepping: 7
|
|
186
|
+
CPU MHz: 2965.749
|
|
187
|
+
CPU max MHz: 4000.0000
|
|
188
|
+
CPU min MHz: 1000.0000
|
|
189
|
+
BogoMIPS: 5400.00
|
|
190
|
+
Virtualization: VT-x
|
|
191
|
+
L1d cache: 32K
|
|
192
|
+
L1i cache: 32K
|
|
193
|
+
|
|
194
|
+
* @param {stdout of the run_cmd} stdout
|
|
195
|
+
* @param {delimiter to split} delimiter
|
|
196
|
+
* @param {lines to retrieve} lines
|
|
197
|
+
* @param {only retrieve the value that has the same property in config} config
|
|
198
|
+
* @returns
|
|
199
|
+
*/
|
|
200
|
+
const read_key_value_line = (stdout, delimiter = ":", lines, config, exclude_mode) => {
|
|
201
|
+
const obj = {};
|
|
202
|
+
if (!stdout) {
|
|
203
|
+
return obj;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const contents = stdout.toString().split(/(?:\r\n|\r|\n)/g);
|
|
207
|
+
const line_texts = lines ? get_lines(contents, lines) : contents;
|
|
208
|
+
line_texts.forEach(content => {
|
|
209
|
+
const key_value = content.split(delimiter);
|
|
210
|
+
if (key_value.length == 2) {
|
|
211
|
+
const key = key_value[0].trim();
|
|
212
|
+
if (key && !config || (exclude_mode != true && config && config[key]) || exclude_mode == true && config && !config[`!${key}`]) {
|
|
213
|
+
obj[key] = key_value[1].trim();
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
return obj;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Use delimeter to split the line and retrieve the info
|
|
223
|
+
*
|
|
224
|
+
MODEL SIZE
|
|
225
|
+
INTEL SSDSC2KB03 3.5T
|
|
226
|
+
INTEL SSDPE2KE032T7 2.9T
|
|
227
|
+
|
|
228
|
+
* @param {stdout of the run_cmd} stdout
|
|
229
|
+
* @param {the attribute keys} keys
|
|
230
|
+
* @param {the lines to ignore} ignore
|
|
231
|
+
* @param {delimiter to split the line} delimiter
|
|
232
|
+
* @returns
|
|
233
|
+
*/
|
|
234
|
+
const read_obj_line = (stdout, keys, ignore = 1, delimiter = " ") => {
|
|
235
|
+
const results = [];
|
|
236
|
+
if (!stdout) {
|
|
237
|
+
return results;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const contents = stdout.toString().split(/(?:\r\n|\r|\n)/g);
|
|
241
|
+
const line_texts = contents.slice(ignore);
|
|
242
|
+
line_texts.forEach(content => {
|
|
243
|
+
const values = content.split(delimiter);
|
|
244
|
+
if (values && values.length > 0 && values[0].trim().length > 0) {
|
|
245
|
+
const obj = {};
|
|
246
|
+
const attrs = values.filter(f => f.trim().length > 0);
|
|
247
|
+
for (let i = 0; i < keys.length; i++) {
|
|
248
|
+
const key = keys[i];
|
|
249
|
+
const value = attrs[i];
|
|
250
|
+
value && (obj[key] = value.trim());
|
|
251
|
+
}
|
|
252
|
+
results.push(obj);
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
return results;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Retrive attributes value and put it to obj
|
|
260
|
+
* @param {host info,contains user,ip and password} host
|
|
261
|
+
* @param {*} attrs {name:"attr name",cmd:"command to get the attr"}
|
|
262
|
+
*/
|
|
263
|
+
const get_system_attributes = async (host, attrs) => {
|
|
264
|
+
const obj = {};
|
|
265
|
+
for (let i = 0; i < attrs.length; i++) {
|
|
266
|
+
const attr = attrs[i];
|
|
267
|
+
const value = await run_simple_cmd(host, attr.cmd);
|
|
268
|
+
value && (obj[attr.name] = value);
|
|
269
|
+
}
|
|
270
|
+
return obj;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const stop_process = async (host, process_name, stop_cmd, using_full) => {
|
|
274
|
+
const grep_cmd = using_full == true ? `pgrep -f "${process_name}" | wc -l` : `pgrep ${process_name} | wc -l`;
|
|
275
|
+
const { stdout } = await run_script(host, grep_cmd);
|
|
276
|
+
const has_process = stdout && parseInt(stdout) > 0;
|
|
277
|
+
if (has_process) {
|
|
278
|
+
await run_script(host, stop_cmd);
|
|
279
|
+
}
|
|
280
|
+
return has_process;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
module.exports = { stop_process, scp, run_script, run_script_file, run_simple_cmd, run_local_cmd, run_simple_local_cmd, get_info, get_system_attributes, read_key_value_line, read_obj_line };
|
package/core/chart.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const { has_value } = require("./validate");
|
|
2
|
+
|
|
3
|
+
const set_chart_header = (arr1, prefix) => {
|
|
4
|
+
if (!arr1 || arr1.length < 1) {
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
const headers = arr1[0];
|
|
8
|
+
if (!headers || headers.length < 1) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
for (let i = 1; i < headers.length; i++) {
|
|
12
|
+
headers[i] = `${prefix}${headers[i]}`;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const merge_chart_data = (arr1, arr2) => {
|
|
17
|
+
if (!arr1 || arr1.length < 2 || !arr2 || arr2.length < 2) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const max = Math.max(arr1.length, arr2.length);
|
|
22
|
+
const arr1_cols = arr1[0].length;
|
|
23
|
+
const arr2_cols = arr2[0].length;
|
|
24
|
+
for (let i = 0; i < max; i++) {
|
|
25
|
+
if (!has_value(arr1[i])) {
|
|
26
|
+
arr1[i] = [...new Array(arr1_cols)].map(o => "");
|
|
27
|
+
arr1[i][0] = arr2[i][0];
|
|
28
|
+
}
|
|
29
|
+
if (!has_value(arr2[i])) {
|
|
30
|
+
arr2[i] = [...new Array(arr2_cols)].map(o => "");
|
|
31
|
+
}
|
|
32
|
+
arr1[i] = [...arr1[i], ...arr2[i].splice(1)];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
module.exports = { set_chart_header, merge_chart_data }
|
package/core/cron.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const node_cron = require('node-cron');
|
|
2
|
+
|
|
3
|
+
const init_cron = async (crons, tasks) => {
|
|
4
|
+
crons.forEach((cron, index) => {
|
|
5
|
+
const schedule = node_cron.schedule(cron, () => { tasks[index](); }, { scheduled: true, timezone: "Asia/Shanghai" });
|
|
6
|
+
schedule.start();
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
module.exports = { init_cron };
|
package/core/lhs.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
|
|
2
|
+
const vm = require('node:vm');
|
|
3
|
+
const { range, scale, space } = require("./number");
|
|
4
|
+
|
|
5
|
+
const get_context = () => { return { range: range, scale: scale, space: space } }
|
|
6
|
+
|
|
7
|
+
const run_in_context = (code, ctx) => {
|
|
8
|
+
vm.createContext(ctx);
|
|
9
|
+
vm.runInContext(code, ctx);
|
|
10
|
+
return ctx;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const verify_template = (template, knob) => {
|
|
14
|
+
try {
|
|
15
|
+
run_in_context("__output__=`" + template + "`;", knob);
|
|
16
|
+
} catch (err) {
|
|
17
|
+
return err.message;
|
|
18
|
+
}
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const execute_template = (template, knob) => {
|
|
23
|
+
const ctx = run_in_context("__output__=`" + template + "`;", knob);
|
|
24
|
+
return ctx["__output__"];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
module.exports = { get_context, run_in_context, verify_template, execute_template }
|
package/core/meta.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const { is_undefined } = require('./validate');
|
|
2
2
|
const { get_type } = require('./type');
|
|
3
|
+
const { is_valid_role } = require('../setting');
|
|
3
4
|
|
|
4
5
|
const meta_manager = {};
|
|
5
6
|
/**
|
|
@@ -20,7 +21,7 @@ const meta_manager = {};
|
|
|
20
21
|
*
|
|
21
22
|
*/
|
|
22
23
|
const field_attrs = ["name", "type", "required", "ref", "link", "delete", "create", "list", "search", "update", "clone", "sys", "secure", "group"];
|
|
23
|
-
const meta_attrs = ["collection", "primary_keys", "fields", "creatable", "readable", "updatable", "deleteable", "cloneable", "after_read",
|
|
24
|
+
const meta_attrs = ["collection", "roles", "primary_keys", "fields", "creatable", "readable", "updatable", "deleteable", "cloneable", "after_read",
|
|
24
25
|
"before_create", "after_create", "before_clone", "after_clone", "before_update", "after_update", "before_delete", "after_delete", "create", "clone", "update", "batch_update", "after_batch_update", "delete",
|
|
25
26
|
"ref_label", "ref_filter", "route", "user_field"];
|
|
26
27
|
|
|
@@ -200,6 +201,7 @@ class EntityMeta {
|
|
|
200
201
|
constructor(meta) {
|
|
201
202
|
this.meta = meta;
|
|
202
203
|
this.collection = this.meta.collection;
|
|
204
|
+
this.roles = this.meta.roles;
|
|
203
205
|
|
|
204
206
|
this.creatable = is_undefined(meta.creatable) ? false : meta.creatable;
|
|
205
207
|
this.readable = is_undefined(meta.readable) ? false : meta.readable;
|
|
@@ -281,6 +283,19 @@ class EntityMeta {
|
|
|
281
283
|
});
|
|
282
284
|
}
|
|
283
285
|
|
|
286
|
+
if (this.roles) {
|
|
287
|
+
if (!Array.isArray(this.roles)) {
|
|
288
|
+
throw new Error("roles of meta [" + this.collection + "] should be array");
|
|
289
|
+
}
|
|
290
|
+
this.roles.forEach(role => {
|
|
291
|
+
const role_config = role.split(":");
|
|
292
|
+
const role_name = role_config[0];
|
|
293
|
+
if (!is_valid_role(role_name)) {
|
|
294
|
+
throw new Error("role [" + role_name + "] not defined in setting");
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
|
|
284
299
|
if (this.ref_label && !this.field_names.includes(this.ref_label)) {
|
|
285
300
|
throw new Error("ref_label [" + this.ref_label + "] configured in meta:" + this.collection + " not found in field names");
|
|
286
301
|
}
|
package/core/msg.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const wxm = require('wxmnode');
|
|
2
|
+
|
|
3
|
+
const init_wxm = (name, password) => {
|
|
4
|
+
wxm.init(name, password);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const send_msg = async (content, type, detail) => {
|
|
8
|
+
return await wxm.sendMsg(content, type, detail);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
module.exports = { init_wxm, send_msg }
|
package/http/session.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const express_session = require('express-session');
|
|
2
2
|
const MongoStore = require('connect-mongo');
|
|
3
|
-
const { get_settings } = require('../setting');
|
|
3
|
+
const { get_settings, is_valid_role, is_root_role } = require('../setting');
|
|
4
4
|
|
|
5
5
|
const init_session = (app) => {
|
|
6
6
|
const server = get_settings().server;
|
|
@@ -24,9 +24,45 @@ const get_session_userid = (req) => {
|
|
|
24
24
|
return user ? user.id : null;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
const get_session_user_role = (req) => {
|
|
28
|
+
const user = req && req.session ? req.session.user : null;
|
|
29
|
+
return user ? user.role : null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
//b:batch mode, c:create, d:delete, e:export, i:import, o:clone, p:page, r: refresh, s:search, u:update
|
|
33
|
+
const mode_all = "bcdeiorsu";
|
|
34
|
+
|
|
35
|
+
const get_user_role_mode = (req, roles) => {
|
|
36
|
+
const user_role = get_session_user_role(req);
|
|
37
|
+
if (!user_role) {
|
|
38
|
+
return "";
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (is_root_role(user_role)) {
|
|
42
|
+
return mode_all;
|
|
43
|
+
} else if (is_valid_role(user_role)) {
|
|
44
|
+
for (let i = 0; i < roles.length; i++) {
|
|
45
|
+
const role = roles[i];
|
|
46
|
+
const role_settings = role.split(":");
|
|
47
|
+
const role_name = role_settings[0];
|
|
48
|
+
const role_mode = role_settings[1];
|
|
49
|
+
if (user_role == role_name) {
|
|
50
|
+
return role_mode;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return "";
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const check_user_role = (req, roles, mode) => {
|
|
59
|
+
const role_mode = get_user_role_mode(req, roles);
|
|
60
|
+
return role_mode.includes(mode);
|
|
61
|
+
}
|
|
62
|
+
|
|
27
63
|
const get_session_user_groups = (req) => {
|
|
28
64
|
const group = req && req.session ? req.session.group : null;
|
|
29
65
|
return group && Array.isArray(group) ? group : null;
|
|
30
66
|
}
|
|
31
67
|
|
|
32
|
-
module.exports = { init_session, get_session_userid, get_session_user_groups };
|
|
68
|
+
module.exports = { init_session, get_session_userid, get_session_user_role, get_session_user_groups, check_user_role, get_user_role_mode };
|
package/index.js
CHANGED
|
@@ -8,8 +8,13 @@ const { EntityMeta, get_entity_meta } = require('./core/meta');
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
const array = require('./core/array');
|
|
11
|
+
const bash = require('./core/bash');
|
|
12
|
+
const chart = require('./core/chart');
|
|
13
|
+
const cron = require('./core/cron');
|
|
11
14
|
const date = require('./core/date');
|
|
12
15
|
const file = require('./core/file');
|
|
16
|
+
const lhs = require('./core/lhs');
|
|
17
|
+
const msg = require('./core/msg');
|
|
13
18
|
const number = require('./core/number');
|
|
14
19
|
const obj = require('./core/obj');
|
|
15
20
|
const random = require('./core/random');
|
|
@@ -26,6 +31,6 @@ const { log_debug, log_info, log_warn, log_error, is_log_debug, is_log_info, is_
|
|
|
26
31
|
|
|
27
32
|
module.exports = {
|
|
28
33
|
init_settings, init_express_server, init_router, register_type, get_type, get_db,
|
|
29
|
-
Entity, EntityMeta, get_entity_meta, array, date, file, number, obj, random, thread, validate, code, err, params, context, gridfs, gen_i18n,
|
|
34
|
+
Entity, EntityMeta, get_entity_meta, array, bash, chart, cron, date, file, lhs, msg, number, obj, random, thread, validate, code, err, params, context, gridfs, gen_i18n,
|
|
30
35
|
log_debug, log_info, log_warn, log_error, is_log_debug, is_log_info, is_log_warn, is_log_error, get_session_userid, oid_queries, oid_query
|
|
31
36
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hola-server",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.6",
|
|
4
4
|
"description": "a meta programming framework used to build nodejs restful api",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -18,7 +18,9 @@
|
|
|
18
18
|
"mongodb": "^4.7.0",
|
|
19
19
|
"mongoist": "^2.5.4",
|
|
20
20
|
"multer": "^1.4.5-lts.1",
|
|
21
|
-
"unzipper": "^0.10.11"
|
|
21
|
+
"unzipper": "^0.10.11",
|
|
22
|
+
"node-cron": "^3.0.2",
|
|
23
|
+
"wxmnode": "^1.0.5"
|
|
22
24
|
},
|
|
23
25
|
"devDependencies": {
|
|
24
26
|
"chai": "^4.3.6",
|
package/router/clone.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const { set_file_fields, save_file_fields_to_db } = require('../db/gridfs');
|
|
2
|
-
const { SUCCESS, NO_PARAMS } = require('../http/code');
|
|
3
|
-
const { get_session_userid } = require('../http/session');
|
|
2
|
+
const { SUCCESS, NO_PARAMS, NO_RIGHTS } = require('../http/code');
|
|
3
|
+
const { get_session_userid, check_user_role } = require('../http/session');
|
|
4
4
|
const { wrap_http } = require('../http/error');
|
|
5
5
|
const { post_params, required_post_params } = require('../http/params');
|
|
6
6
|
const { has_value } = require('../core/validate');
|
|
@@ -19,6 +19,14 @@ const init_clone_router = function (router, meta) {
|
|
|
19
19
|
const cp_upload = meta.upload_fields.length > 0 ? upload_file.fields(meta.upload_fields) : upload_file.none();
|
|
20
20
|
|
|
21
21
|
router.post('/clone', cp_upload, wrap_http(async function (req, res) {
|
|
22
|
+
if (meta.roles) {
|
|
23
|
+
const has_right = check_user_role(req, meta.roles, "o");
|
|
24
|
+
if (!has_right) {
|
|
25
|
+
res.json({ code: NO_RIGHTS, err: "no rights error" });
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
22
30
|
let params = required_post_params(req, ["_id"]);
|
|
23
31
|
if (params === null) {
|
|
24
32
|
res.json({ code: NO_PARAMS, err: '[_id] checking params are failed!' });
|
package/router/create.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const { set_file_fields, save_file_fields_to_db } = require('../db/gridfs');
|
|
2
|
-
const { SUCCESS } = require('../http/code');
|
|
3
|
-
const { get_session_userid } = require('../http/session');
|
|
2
|
+
const { SUCCESS, NO_RIGHTS } = require('../http/code');
|
|
3
|
+
const { get_session_userid, check_user_role } = require('../http/session');
|
|
4
4
|
const { wrap_http } = require('../http/error');
|
|
5
5
|
const { post_params } = require('../http/params');
|
|
6
6
|
const { has_value } = require('../core/validate');
|
|
@@ -19,6 +19,14 @@ const init_create_router = function (router, meta) {
|
|
|
19
19
|
const cp_upload = meta.upload_fields.length > 0 ? upload_file.fields(meta.upload_fields) : upload_file.none();
|
|
20
20
|
|
|
21
21
|
router.post('/create', cp_upload, wrap_http(async function (req, res) {
|
|
22
|
+
if (meta.roles) {
|
|
23
|
+
const has_right = check_user_role(req, meta.roles, "c");
|
|
24
|
+
if (!has_right) {
|
|
25
|
+
res.json({ code: NO_RIGHTS, err: "no rights error" });
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
22
30
|
const param_obj = post_params(req, meta.field_names);
|
|
23
31
|
set_file_fields(meta, req, param_obj);
|
|
24
32
|
|
package/router/delete.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const { required_post_params } = require('../http/params');
|
|
2
2
|
const { has_value } = require('../core/validate');
|
|
3
|
-
const { NO_PARAMS } = require('../http/code');
|
|
3
|
+
const { NO_PARAMS, NO_RIGHTS } = require('../http/code');
|
|
4
|
+
const { check_user_role } = require('../http/session');
|
|
4
5
|
const { wrap_http } = require('../http/error');
|
|
5
6
|
const { Entity } = require('../db/entity');
|
|
6
7
|
|
|
@@ -13,6 +14,14 @@ const init_delete_router = function (router, meta) {
|
|
|
13
14
|
const entity = new Entity(meta);
|
|
14
15
|
|
|
15
16
|
router.post('/delete', wrap_http(async function (req, res) {
|
|
17
|
+
if (meta.roles) {
|
|
18
|
+
const has_right = check_user_role(req, meta.roles, "d");
|
|
19
|
+
if (!has_right) {
|
|
20
|
+
res.json({ code: NO_RIGHTS, err: "no rights error" });
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
16
25
|
const params = required_post_params(req, ["ids"]);
|
|
17
26
|
if (params === null) {
|
|
18
27
|
res.json({ code: NO_PARAMS, err: ["ids"] });
|
package/router/read.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const { required_post_params, get_params } = require('../http/params');
|
|
2
2
|
const { has_value } = require('../core/validate');
|
|
3
|
-
const { NO_PARAMS, SUCCESS } = require('../http/code');
|
|
4
|
-
const { get_session_userid, get_session_user_groups } = require('../http/session');
|
|
3
|
+
const { NO_PARAMS, SUCCESS, NO_RIGHTS } = require('../http/code');
|
|
4
|
+
const { get_session_userid, get_session_user_groups, check_user_role, get_user_role_mode } = require('../http/session');
|
|
5
5
|
const { wrap_http } = require('../http/error');
|
|
6
6
|
const { Entity } = require('../db/entity');
|
|
7
7
|
|
|
@@ -14,6 +14,15 @@ const init_read_router = function (router, meta) {
|
|
|
14
14
|
const entity = new Entity(meta);
|
|
15
15
|
|
|
16
16
|
router.get('/meta', wrap_http(async function (req, res) {
|
|
17
|
+
if (meta.roles) {
|
|
18
|
+
const has_right = check_user_role(req, meta.roles, "r");
|
|
19
|
+
if (!has_right) {
|
|
20
|
+
res.json({ code: NO_RIGHTS, err: "no rights error" });
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const mode = meta.roles ? get_user_role_mode(req, meta.roles) : "";
|
|
17
26
|
const entity_meta = {
|
|
18
27
|
creatable: meta.creatable,
|
|
19
28
|
readable: meta.readable,
|
|
@@ -24,12 +33,21 @@ const init_read_router = function (router, meta) {
|
|
|
24
33
|
exportable: meta.exportable,
|
|
25
34
|
editable: meta.editable,
|
|
26
35
|
user_field: meta.user_field,
|
|
27
|
-
fields: meta.fields
|
|
36
|
+
fields: meta.fields,
|
|
37
|
+
mode: mode.length > 0 ? mode : null
|
|
28
38
|
}
|
|
29
39
|
res.json({ code: SUCCESS, data: entity_meta });
|
|
30
40
|
}));
|
|
31
41
|
|
|
32
42
|
router.get('/ref', wrap_http(async function (req, res) {
|
|
43
|
+
if (meta.roles) {
|
|
44
|
+
const has_right = check_user_role(req, meta.roles, "r");
|
|
45
|
+
if (!has_right) {
|
|
46
|
+
res.json({ code: NO_RIGHTS, err: "no rights error" });
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
33
51
|
const { ref_by_entity } = get_params(req, ["ref_by_entity"]);
|
|
34
52
|
const list = await entity.get_filtered_ref_labels(ref_by_entity);
|
|
35
53
|
const items = list.map(obj => ({ "text": obj[meta.ref_label], "value": obj["_id"] + "" }));
|
|
@@ -37,6 +55,14 @@ const init_read_router = function (router, meta) {
|
|
|
37
55
|
}));
|
|
38
56
|
|
|
39
57
|
router.post('/list', wrap_http(async function (req, res) {
|
|
58
|
+
if (meta.roles) {
|
|
59
|
+
const has_right = check_user_role(req, meta.roles, "r");
|
|
60
|
+
if (!has_right) {
|
|
61
|
+
res.json({ code: NO_RIGHTS, err: "no rights error" });
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
40
66
|
const query_params = required_post_params(req, ["_query"]);
|
|
41
67
|
if (query_params === null) {
|
|
42
68
|
res.json({ code: NO_PARAMS, err: ["_query"] });
|
|
@@ -71,6 +97,14 @@ const init_read_router = function (router, meta) {
|
|
|
71
97
|
}));
|
|
72
98
|
|
|
73
99
|
router.post('/read_entity', wrap_http(async function (req, res) {
|
|
100
|
+
if (meta.roles) {
|
|
101
|
+
const has_right = check_user_role(req, meta.roles, "r");
|
|
102
|
+
if (!has_right) {
|
|
103
|
+
res.json({ code: NO_RIGHTS, err: "no rights error" });
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
74
108
|
let params = required_post_params(req, ["_id", "attr_names"]);
|
|
75
109
|
if (params === null) {
|
|
76
110
|
res.json({ code: NO_PARAMS, err: '[_id,attr_names] checking params are failed!' });
|
|
@@ -86,6 +120,14 @@ const init_read_router = function (router, meta) {
|
|
|
86
120
|
}));
|
|
87
121
|
|
|
88
122
|
router.post('/read_property', wrap_http(async function (req, res) {
|
|
123
|
+
if (meta.roles) {
|
|
124
|
+
const has_right = check_user_role(req, meta.roles, "r");
|
|
125
|
+
if (!has_right) {
|
|
126
|
+
res.json({ code: NO_RIGHTS, err: "no rights error" });
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
89
131
|
let params = required_post_params(req, ["_id", "attr_names"]);
|
|
90
132
|
if (params === null) {
|
|
91
133
|
res.json({ code: NO_PARAMS, err: '[_id,attr_names] checking params are failed!' });
|
package/router/update.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const { set_file_fields, save_file_fields_to_db } = require('../db/gridfs');
|
|
2
2
|
const { required_post_params, post_update_params } = require('../http/params');
|
|
3
|
-
const { SUCCESS, NO_PARAMS } = require('../http/code');
|
|
3
|
+
const { SUCCESS, NO_PARAMS, NO_RIGHTS } = require('../http/code');
|
|
4
|
+
const { check_user_role } = require('../http/session');
|
|
4
5
|
const { has_value } = require('../core/validate');
|
|
5
6
|
const { wrap_http } = require('../http/error');
|
|
6
7
|
const { Entity } = require('../db/entity');
|
|
@@ -18,6 +19,14 @@ const init_update_router = function (router, meta) {
|
|
|
18
19
|
const cp_upload = meta.upload_fields.length > 0 ? upload_file.fields(meta.upload_fields) : upload_file.none();
|
|
19
20
|
|
|
20
21
|
router.post('/update', cp_upload, wrap_http(async function (req, res) {
|
|
22
|
+
if (meta.roles) {
|
|
23
|
+
const has_right = check_user_role(req, meta.roles, "u");
|
|
24
|
+
if (!has_right) {
|
|
25
|
+
res.json({ code: NO_RIGHTS, err: "no rights error" });
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
21
30
|
let params = required_post_params(req, ["_id"]);
|
|
22
31
|
if (params === null) {
|
|
23
32
|
params = required_post_params(req, meta.primary_keys);
|
package/setting.js
CHANGED
|
@@ -13,6 +13,10 @@ let settings = {
|
|
|
13
13
|
log_level: 0,
|
|
14
14
|
save_db: dev_mode == false,
|
|
15
15
|
},
|
|
16
|
+
roles: [
|
|
17
|
+
{ name: "admin", root: true },
|
|
18
|
+
{ name: "user" }
|
|
19
|
+
],
|
|
16
20
|
server: {
|
|
17
21
|
service_port: 8088,
|
|
18
22
|
client_web_url: ['http://localhost:8080'],
|
|
@@ -39,4 +43,20 @@ const get_settings = () => {
|
|
|
39
43
|
return settings;
|
|
40
44
|
}
|
|
41
45
|
|
|
42
|
-
|
|
46
|
+
const is_valid_role = (role_name) => {
|
|
47
|
+
if (!settings.roles) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
const roles = settings.roles.filter(role => role.name == role_name);
|
|
51
|
+
return roles.length == 1;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const is_root_role = (role_name) => {
|
|
55
|
+
if (!is_valid_role(role_name)) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return settings.roles.filter(role => role.name == role_name)[0].root == true;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
module.exports = { init_settings, get_settings, is_root_role, is_valid_role };
|