@opengis/fastify-table 1.4.51 → 1.4.53
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/config.js +1 -0
- package/index.js +9 -6
- package/package.json +1 -1
- package/server/helpers/format/formatNum.js +59 -59
- package/server/helpers/format/formatNumber.js +1 -0
- package/server/helpers/format/formatUnit.js +4 -2
- package/server/helpers/format/num_format.js +2 -0
- package/server/helpers/funcs/_math.js +4 -4
- package/server/helpers/funcs/contentList.js +6 -10
- package/server/helpers/funcs/ifCond.js +34 -31
- package/server/helpers/funcs/ifCondAnd.js +21 -4
- package/server/helpers/funcs/ifCondOr.js +21 -4
- package/server/helpers/funcs/json.js +1 -1
- package/server/helpers/funcs/round.js +5 -4
- package/server/helpers/funcs/select.js +6 -6
- package/server/helpers/index.js +3 -2
- package/server/helpers/list/tableList.js +2 -0
- package/server/helpers/list/utils/buttonDel.js +2 -2
- package/server/helpers/list/utils/buttonEdit.js +2 -2
- package/server/helpers/string/coalesce.js +13 -5
- package/server/helpers/utils/paddingNumber.js +3 -2
- package/server/plugins/crud/funcs/validateData.js +3 -2
- package/server/plugins/grpc/grpc.js +1 -0
- package/server/plugins/grpc/office2pdf.js +2 -1
- package/server/plugins/policy/sqlInjection.js +1 -0
- package/server/plugins/policy/xssInjection.js +1 -0
- package/server/plugins/table/funcs/getFilterSQL/index.js +2 -2
- package/server/plugins/table/funcs/getFilterSQL/util/formatValue.js +1 -1
- package/server/plugins/table/funcs/getFilterSQL/util/getRangeQuery.js +1 -0
- package/server/plugins/util/funcs/unflattenObject.js +2 -0
- package/server/routes/crud/controllers/update.js +5 -5
- package/server/routes/table/index.js +4 -4
package/config.js
CHANGED
package/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
1
2
|
import path from 'node:path';
|
|
2
3
|
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
3
4
|
import { fileURLToPath } from 'node:url';
|
|
@@ -104,12 +105,14 @@ async function plugin(fastify, opt) {
|
|
|
104
105
|
cronPlugin(fastify, opt);
|
|
105
106
|
loggerPlugin(fastify, opt);
|
|
106
107
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
108
|
+
if (config.rateLimit !== false) {
|
|
109
|
+
await fastify.register(import('@fastify/rate-limit'), {
|
|
110
|
+
max: config.rateLimit?.max || 100,
|
|
111
|
+
timeWindow: config.rateLimit?.timeWindow || '1 minute',
|
|
112
|
+
global: true,
|
|
113
|
+
keyGenerator: (req) => `${req.ip}-${req.raw.url.split('?')[0]}`,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
113
116
|
|
|
114
117
|
if (config.dblist) {
|
|
115
118
|
dblistRoutes(fastify, opt);
|
package/package.json
CHANGED
|
@@ -89,67 +89,67 @@ const mapNumbers = {
|
|
|
89
89
|
};
|
|
90
90
|
const mapOrders = {
|
|
91
91
|
ua: [
|
|
92
|
-
{
|
|
93
|
-
{
|
|
94
|
-
{
|
|
95
|
-
{
|
|
96
|
-
{
|
|
92
|
+
{ Gender: true, arrStates: ['', '', ''] },
|
|
93
|
+
{ Gender: true, arrStates: ['тисяча', 'тисячі', 'тисяч'] },
|
|
94
|
+
{ Gender: false, arrStates: ['мільйон', 'мільйона', 'мільйонів'] },
|
|
95
|
+
{ Gender: false, arrStates: ['мільярд', 'мільярда', 'мільярдів'] },
|
|
96
|
+
{ Gender: false, arrStates: ['триліон', 'триліона', 'триліонів'] },
|
|
97
97
|
{
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
Gender: true,
|
|
99
|
+
arrStates: {
|
|
100
100
|
uah: ['грн.', 'грн.', 'грн.'],
|
|
101
101
|
rur: ['руб.', 'руб.', 'руб.'],
|
|
102
102
|
},
|
|
103
|
-
|
|
103
|
+
bAddZeroWord: true,
|
|
104
104
|
},
|
|
105
105
|
{
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
Gender: true,
|
|
107
|
+
arrStates: ['ціла', 'цілих', 'цілих'],
|
|
108
|
+
bAddZeroWord: true,
|
|
109
109
|
},
|
|
110
|
-
{
|
|
110
|
+
{ Gender: true, arrStates: ['', '', ''], bAddZeroWord: true },
|
|
111
111
|
{
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
112
|
+
Gender: true,
|
|
113
|
+
arrStates: ['дол.', 'дол.', 'дол.'],
|
|
114
|
+
bAddZeroWord: true,
|
|
115
115
|
},
|
|
116
116
|
{
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
117
|
+
Gender: true,
|
|
118
|
+
arrStates: ['грн.', 'грн.', 'грн.'],
|
|
119
|
+
bAddZeroWord: true,
|
|
120
120
|
},
|
|
121
121
|
],
|
|
122
122
|
ru: [
|
|
123
|
-
{
|
|
124
|
-
{
|
|
125
|
-
{
|
|
126
|
-
{
|
|
127
|
-
{
|
|
123
|
+
{ Gender: true, arrStates: ['', '', ''] },
|
|
124
|
+
{ Gender: true, arrStates: ['тысяча', 'тысячи', 'тысяч'] },
|
|
125
|
+
{ Gender: false, arrStates: ['миллион', 'миллиона', 'миллионов'] },
|
|
126
|
+
{ Gender: false, arrStates: ['миллиард', 'миллиарда', 'миллиардов'] },
|
|
127
|
+
{ Gender: false, arrStates: ['триллион', 'триллиона', 'триллионов'] },
|
|
128
128
|
{
|
|
129
|
-
|
|
130
|
-
|
|
129
|
+
Gender: true,
|
|
130
|
+
arrStates: {
|
|
131
131
|
uah: ['грн.', 'грн.', 'грн.'],
|
|
132
132
|
rur: ['руб.', 'руб.', 'руб.'],
|
|
133
133
|
usd: ['дол.', 'дол.', 'дол.'],
|
|
134
134
|
},
|
|
135
|
-
|
|
135
|
+
bAddZeroWord: true,
|
|
136
136
|
},
|
|
137
137
|
{
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
138
|
+
Gender: true,
|
|
139
|
+
arrStates: ['целых', 'целых', 'целых'],
|
|
140
|
+
bAddZeroWord: true,
|
|
141
141
|
},
|
|
142
|
-
{
|
|
142
|
+
{ Gender: true, arrStates: ['', '', ''], bAddZeroWord: true },
|
|
143
143
|
{
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
144
|
+
Gender: true,
|
|
145
|
+
arrStates: ['дол.', 'дол.', 'дол.'],
|
|
146
|
+
bAddZeroWord: true,
|
|
147
147
|
},
|
|
148
148
|
],
|
|
149
149
|
};
|
|
150
150
|
const objCur = {
|
|
151
|
-
|
|
152
|
-
|
|
151
|
+
Gender: false,
|
|
152
|
+
arrStates: {
|
|
153
153
|
uah: ['грн.', 'грн.', 'грн.'],
|
|
154
154
|
rur: ['руб.', 'руб.', 'руб.'],
|
|
155
155
|
usd: ['дол.', 'дол.', 'дол.'],
|
|
@@ -157,15 +157,15 @@ const objCur = {
|
|
|
157
157
|
},
|
|
158
158
|
};
|
|
159
159
|
const objCoin = {
|
|
160
|
-
|
|
161
|
-
|
|
160
|
+
Gender: false,
|
|
161
|
+
arrStates: {
|
|
162
162
|
uah: 'коп.',
|
|
163
163
|
rur: 'коп.',
|
|
164
164
|
usd: 'цен.',
|
|
165
165
|
num: { ru: 'сот.', ua: 'сот.', en: 'hund.' },
|
|
166
166
|
},
|
|
167
167
|
};
|
|
168
|
-
|
|
168
|
+
// функции которые отвечают за форматирование
|
|
169
169
|
/**
|
|
170
170
|
* Formatting from number to string
|
|
171
171
|
*
|
|
@@ -197,17 +197,17 @@ function value(dVal, bGender, lang) {
|
|
|
197
197
|
* from0To999(arrRet, 404,
|
|
198
198
|
* oObjDesc:
|
|
199
199
|
* {
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
200
|
+
* Gender: true,
|
|
201
|
+
* bAddZeroWord: undefined,
|
|
202
|
+
* arrStates: ['','',''],
|
|
203
203
|
* },
|
|
204
204
|
* lang: 'ru'
|
|
205
205
|
* })
|
|
206
206
|
* @param {Array} arrRet
|
|
207
207
|
* @param {Number} fValue
|
|
208
|
-
* @param {Object} [oObjDesc.
|
|
209
|
-
* @param {Object} [oObjDesc.
|
|
210
|
-
* @param {Object} [oObjDesc.
|
|
208
|
+
* @param {Object} [oObjDesc.Gender]
|
|
209
|
+
* @param {Object} [oObjDesc.bAddZeroWord]
|
|
210
|
+
* @param {Object} [oObjDesc.arrStates]
|
|
211
211
|
* @param oObjDesc
|
|
212
212
|
* @param {String} lang
|
|
213
213
|
*/
|
|
@@ -216,32 +216,32 @@ function from0To999(arrRet, fValue, oObjDesc, lang) {
|
|
|
216
216
|
let nCurrState = 2;
|
|
217
217
|
if (Math.floor(fValueNew / 100) > 0) {
|
|
218
218
|
const fCurr = Math.floor(fValueNew / 100) * 100;
|
|
219
|
-
arrRet.push(value(fCurr, oObjDesc.
|
|
219
|
+
arrRet.push(value(fCurr, oObjDesc.Gender, lang));
|
|
220
220
|
nCurrState = mapNumbers[lang][fCurr][0];
|
|
221
221
|
fValueNew -= fCurr;
|
|
222
222
|
}
|
|
223
223
|
if (fValueNew === 0) {
|
|
224
|
-
arrRet.push(value(fValueNew, oObjDesc.
|
|
224
|
+
arrRet.push(value(fValueNew, oObjDesc.Gender, lang));
|
|
225
225
|
nCurrState = mapNumbers[lang][fValueNew][0];
|
|
226
226
|
}
|
|
227
|
-
|
|
228
|
-
if (Math.floor(fValueNew) > 0 || oObjDesc.
|
|
229
|
-
arrRet.push(value(fValueNew, oObjDesc.
|
|
227
|
+
else if (fValueNew < 20) {
|
|
228
|
+
if (Math.floor(fValueNew) > 0 || oObjDesc.bAddZeroWord) {
|
|
229
|
+
arrRet.push(value(fValueNew, oObjDesc.Gender, lang));
|
|
230
230
|
nCurrState = mapNumbers[lang][fValueNew][0];
|
|
231
231
|
}
|
|
232
232
|
}
|
|
233
|
-
|
|
233
|
+
else {
|
|
234
234
|
const fCurr = Math.floor(fValueNew / 10) * 10;
|
|
235
|
-
arrRet.push(value(fCurr, oObjDesc.
|
|
235
|
+
arrRet.push(value(fCurr, oObjDesc.Gender, lang));
|
|
236
236
|
nCurrState = mapNumbers[lang][fCurr][0];
|
|
237
237
|
fValueNew -= fCurr;
|
|
238
238
|
|
|
239
239
|
if (Math.floor(fValueNew) > 0) {
|
|
240
|
-
arrRet.push(value(fValueNew, oObjDesc.
|
|
240
|
+
arrRet.push(value(fValueNew, oObjDesc.Gender, lang));
|
|
241
241
|
nCurrState = mapNumbers[lang][fValueNew][0];
|
|
242
242
|
}
|
|
243
243
|
}
|
|
244
|
-
arrRet.push(oObjDesc.
|
|
244
|
+
arrRet.push(oObjDesc.arrStates[nCurrState]);
|
|
245
245
|
}
|
|
246
246
|
|
|
247
247
|
/**
|
|
@@ -289,11 +289,11 @@ function floatToSamplesInWordsUkr(fAmount, resultStr, exp, lang, currency) {
|
|
|
289
289
|
/%d/,
|
|
290
290
|
Math.floor(parseInt(fAmount, 10) + 0.005),
|
|
291
291
|
);
|
|
292
|
-
if (currency !== 'num' && objCur.
|
|
293
|
-
|
|
292
|
+
if (currency !== 'num' && objCur.arrStates[currency]) { resultStrNew = resultStrNew.replace(/%curr/, objCur.arrStates[currency][0]); }
|
|
293
|
+
else {
|
|
294
294
|
resultStrNew = resultStrNew.replace(
|
|
295
295
|
/%curr/,
|
|
296
|
-
objCur.
|
|
296
|
+
objCur.arrStates[lang === 'ru' ? 'rur' : lang][0],
|
|
297
297
|
);
|
|
298
298
|
}
|
|
299
299
|
|
|
@@ -309,11 +309,11 @@ function floatToSamplesInWordsUkr(fAmount, resultStr, exp, lang, currency) {
|
|
|
309
309
|
|
|
310
310
|
resultStrNew = resultStrNew.replace(/%f/, fDec);
|
|
311
311
|
|
|
312
|
-
if (currency !== 'num' && objCur.
|
|
313
|
-
|
|
312
|
+
if (currency !== 'num' && objCur.arrStates[currency]) { resultStrNew = resultStrNew.replace(/%coin/, objCoin.arrStates[currency]); }
|
|
313
|
+
else {
|
|
314
314
|
resultStrNew = resultStrNew.replace(
|
|
315
315
|
/%coin/,
|
|
316
|
-
objCoin.
|
|
316
|
+
objCoin.arrStates[lang === 'ru' ? 'rur' : lang],
|
|
317
317
|
);
|
|
318
318
|
}
|
|
319
319
|
return resultStrNew;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/* eslint-disable no-restricted-globals */
|
|
2
|
+
/* eslint-disable no-param-reassign */
|
|
1
3
|
/**
|
|
2
4
|
* Повертає розмір файлу на диску у встановлених одиницях вимірювання об'єму файлу.
|
|
3
5
|
*
|
|
@@ -17,13 +19,13 @@ export default function formatUnit(data, options) {
|
|
|
17
19
|
data = parseFloat(data);
|
|
18
20
|
if (isNaN(data)) return data;
|
|
19
21
|
|
|
20
|
-
const
|
|
22
|
+
const UNIT = {
|
|
21
23
|
B: {
|
|
22
24
|
4: 'TB', 3: 'GB', 2: 'MB', 1: 'KB', 0: 'B',
|
|
23
25
|
},
|
|
24
26
|
};
|
|
25
27
|
|
|
26
|
-
const unit =
|
|
28
|
+
const unit = UNIT[options.hash.unit] || UNIT.B;
|
|
27
29
|
const number = options.hash.number || 0;
|
|
28
30
|
|
|
29
31
|
for (let i = 4; i >= 0; i -= 1) {
|
|
@@ -15,12 +15,12 @@
|
|
|
15
15
|
* @param {Object} operator Оператор для дії з числами
|
|
16
16
|
* @param {Object} arg1 Перше число для дії
|
|
17
17
|
* @param {Object} arg2 Друге число для дії
|
|
18
|
-
* @param {Array} args[0]
|
|
19
|
-
* @param {Array} args[1]
|
|
20
|
-
* @param {Array} args[2]
|
|
18
|
+
* @param {Array} args[0] Перше число для дії
|
|
19
|
+
* @param {Array} args[1] Оператор для дії з числами
|
|
20
|
+
* @param {Array} args[2] Друге число для дії
|
|
21
21
|
* @returns {String} Returns HTML
|
|
22
22
|
*/
|
|
23
|
-
export default function
|
|
23
|
+
export default function math(...args) {
|
|
24
24
|
const options = args.pop();
|
|
25
25
|
const opt = options.hash;
|
|
26
26
|
|
|
@@ -25,9 +25,9 @@ const maxLimit = 100;
|
|
|
25
25
|
* @returns {String} Returns HTML
|
|
26
26
|
*/
|
|
27
27
|
export default async function contentList(options) {
|
|
28
|
-
const {
|
|
29
|
-
|
|
30
|
-
} = options.hash;
|
|
28
|
+
const {
|
|
29
|
+
table, limit, query, order, sql, debug,
|
|
30
|
+
} = options.hash;
|
|
31
31
|
if (!table) { return 'Table undefined'; }
|
|
32
32
|
|
|
33
33
|
try {
|
|
@@ -35,11 +35,7 @@ export default async function contentList(options) {
|
|
|
35
35
|
|
|
36
36
|
const hasBrackets = table.trim().startsWith('(') && table.trim().endsWith(')');
|
|
37
37
|
|
|
38
|
-
const
|
|
39
|
-
const _limit = limit !== undefined && limit !== null ? Math.min(maxLimit, +limit) : 15;
|
|
40
|
-
const _order = order ? `order by ${order}` : '';
|
|
41
|
-
|
|
42
|
-
const SQL = `select *,${pg.pk[table] || '1'}::text from ${hasBrackets ? `${table} t` : table} ${where} ${_order} limit ${_limit}`;
|
|
38
|
+
const SQL = `select *,${pg.pk[table] || '1'}::text from ${hasBrackets ? `${table} t` : table} where ${query || '1=1'} ${order ? `order by ${order}` : ''} limit ${limit !== undefined && limit !== null ? Math.min(maxLimit, +limit) : 15}`;
|
|
43
39
|
const compiledSQL = Handlebars.compile(SQL)(options.data.root);
|
|
44
40
|
|
|
45
41
|
if (sql) {
|
|
@@ -54,8 +50,8 @@ export default async function contentList(options) {
|
|
|
54
50
|
}
|
|
55
51
|
|
|
56
52
|
return options.fn(data);
|
|
57
|
-
}
|
|
58
|
-
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
59
55
|
return `Сталася помилка, зверніться до відділу підтримки.<!-- err: ${err.toString()} -->`;
|
|
60
56
|
}
|
|
61
57
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable no-param-reassign */
|
|
1
2
|
/**
|
|
2
3
|
* Перетинає два масиви
|
|
3
4
|
*
|
|
@@ -32,75 +33,77 @@ function intersect(a, b) {
|
|
|
32
33
|
* @example
|
|
33
34
|
* {{#ifCond 'debug' 'in' @root.setting.core.setting}}Умова виконана{{^}}Не виконана умова{{/ifCond}}
|
|
34
35
|
* @param {Array} args Параметри для значень і умов
|
|
35
|
-
* @param {Array} args[0]
|
|
36
|
-
* @param {Array} args[1]
|
|
37
|
-
* @param {Array} args[2]
|
|
36
|
+
* @param {Array} args[0] Перше значення
|
|
37
|
+
* @param {Array} args[1] Оператор
|
|
38
|
+
* @param {Array} args[2] Друге значення
|
|
38
39
|
* @returns {String} Returns HTML
|
|
39
40
|
*/
|
|
40
41
|
export default function ifCond(v1, operator, v2, options) {
|
|
41
|
-
const
|
|
42
|
+
const obj = this;
|
|
42
43
|
|
|
43
44
|
const isEmpty = (val) => val === null || val === undefined || (Array.isArray(val) && val.length === 0) || val === '';
|
|
44
45
|
|
|
45
46
|
switch (operator) {
|
|
46
47
|
case '==':
|
|
47
|
-
|
|
48
|
+
// eslint-disable-next-line eqeqeq
|
|
49
|
+
return (v1 == v2) ? options.fn(obj) : options.inverse(obj);
|
|
48
50
|
case '!=':
|
|
49
|
-
|
|
51
|
+
// eslint-disable-next-line eqeqeq
|
|
52
|
+
return (v1 != v2) ? options.fn(obj) : options.inverse(obj);
|
|
50
53
|
case '===':
|
|
51
|
-
return (v1 === v2) ? options.fn(
|
|
54
|
+
return (v1 === v2) ? options.fn(obj) : options.inverse(obj);
|
|
52
55
|
case '!==':
|
|
53
|
-
return (v1 !== v2) ? options.fn(
|
|
56
|
+
return (v1 !== v2) ? options.fn(obj) : options.inverse(obj);
|
|
54
57
|
case '&&':
|
|
55
|
-
return (v1 && v2) ? options.fn(
|
|
58
|
+
return (v1 && v2) ? options.fn(obj) : options.inverse(obj);
|
|
56
59
|
case '||':
|
|
57
|
-
return (v1 || v2) ? options.fn(
|
|
60
|
+
return (v1 || v2) ? options.fn(obj) : options.inverse(obj);
|
|
58
61
|
case '<':
|
|
59
|
-
return (v1 < v2) ? options.fn(
|
|
62
|
+
return (v1 < v2) ? options.fn(obj) : options.inverse(obj);
|
|
60
63
|
case '<=':
|
|
61
|
-
return (v1 <= v2) ? options.fn(
|
|
64
|
+
return (v1 <= v2) ? options.fn(obj) : options.inverse(obj);
|
|
62
65
|
case '>':
|
|
63
|
-
return (v1 > v2) ? options.fn(
|
|
66
|
+
return (v1 > v2) ? options.fn(obj) : options.inverse(obj);
|
|
64
67
|
case '>=':
|
|
65
|
-
return (v1 >= v2) ? options.fn(
|
|
68
|
+
return (v1 >= v2) ? options.fn(obj) : options.inverse(obj);
|
|
66
69
|
case '&':
|
|
67
70
|
return (!isEmpty(v1) && !isEmpty(v2) && intersect(v1, v2).length !== 0)
|
|
68
|
-
? options.fn(
|
|
69
|
-
: options.inverse(
|
|
71
|
+
? options.fn(obj)
|
|
72
|
+
: options.inverse(obj);
|
|
70
73
|
case '!~':
|
|
71
74
|
return (v1 || '').indexOf(v2) === -1
|
|
72
|
-
? options.fn(
|
|
73
|
-
: options.inverse(
|
|
75
|
+
? options.fn(obj)
|
|
76
|
+
: options.inverse(obj);
|
|
74
77
|
case '~':
|
|
75
78
|
return (v1 || '').indexOf(v2) !== -1
|
|
76
|
-
? options.fn(
|
|
77
|
-
: options.inverse(
|
|
79
|
+
? options.fn(obj)
|
|
80
|
+
: options.inverse(obj);
|
|
78
81
|
case 'period':
|
|
79
82
|
return (!isEmpty(v1) && !isEmpty(v2) && new Date(v1) < new Date() && new Date(v2) > new Date())
|
|
80
|
-
? options.fn(
|
|
81
|
-
: options.inverse(
|
|
83
|
+
? options.fn(obj)
|
|
84
|
+
: options.inverse(obj);
|
|
82
85
|
case 'in': {
|
|
83
86
|
if (typeof v2 === 'string') v2 = v2.split(',').map(item => item.trim());
|
|
84
|
-
if (isEmpty(v1) || isEmpty(v2)) return options.inverse(
|
|
87
|
+
if (isEmpty(v1) || isEmpty(v2)) return options.inverse(obj);
|
|
85
88
|
|
|
86
89
|
if (Array.isArray(v1)) {
|
|
87
90
|
return v1.some((value) => v2.includes(value.toString()))
|
|
88
|
-
? options.fn(
|
|
89
|
-
: options.inverse(
|
|
91
|
+
? options.fn(obj)
|
|
92
|
+
: options.inverse(obj);
|
|
90
93
|
}
|
|
91
94
|
return v2.includes(v1.toString())
|
|
92
|
-
? options.fn(
|
|
93
|
-
: options.inverse(
|
|
95
|
+
? options.fn(obj)
|
|
96
|
+
: options.inverse(obj);
|
|
94
97
|
}
|
|
95
98
|
case 'not in': {
|
|
96
99
|
if (typeof v2 === 'string') v2 = v2.split(',').map(item => item.trim());
|
|
97
|
-
if (isEmpty(v1) || isEmpty(v2)) return options.inverse(
|
|
100
|
+
if (isEmpty(v1) || isEmpty(v2)) return options.inverse(obj);
|
|
98
101
|
|
|
99
102
|
return !v2.includes(v1.toString())
|
|
100
|
-
? options.fn(
|
|
101
|
-
: options.inverse(
|
|
103
|
+
? options.fn(obj)
|
|
104
|
+
: options.inverse(obj);
|
|
102
105
|
}
|
|
103
106
|
default:
|
|
104
|
-
return options.inverse(
|
|
107
|
+
return options.inverse(obj);
|
|
105
108
|
}
|
|
106
109
|
}
|
|
@@ -1,8 +1,23 @@
|
|
|
1
|
+
/* eslint-disable prefer-rest-params */
|
|
1
2
|
function intersect(a, b) {
|
|
2
|
-
|
|
3
|
-
|
|
3
|
+
let aN = [];
|
|
4
|
+
let bN = [];
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
if (Array.isArray(a)) {
|
|
7
|
+
aN = a;
|
|
8
|
+
}
|
|
9
|
+
else if (typeof a === 'string') {
|
|
10
|
+
aN = a.split(',');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (Array.isArray(b)) {
|
|
14
|
+
bN = b;
|
|
15
|
+
}
|
|
16
|
+
else if (typeof b === 'string') {
|
|
17
|
+
bN = b.split(',');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return aN.filter(e => bN.includes(e));
|
|
6
21
|
}
|
|
7
22
|
|
|
8
23
|
/**
|
|
@@ -31,9 +46,11 @@ export default function ifCondAnd() {
|
|
|
31
46
|
|
|
32
47
|
switch (operator) {
|
|
33
48
|
case '==':
|
|
49
|
+
// eslint-disable-next-line eqeqeq
|
|
34
50
|
conditions.push(v1 == v2);
|
|
35
51
|
break;
|
|
36
52
|
case '!=':
|
|
53
|
+
// eslint-disable-next-line eqeqeq
|
|
37
54
|
conditions.push(v1 != v2);
|
|
38
55
|
break;
|
|
39
56
|
case '===':
|
|
@@ -77,7 +94,7 @@ export default function ifCondAnd() {
|
|
|
77
94
|
if (Array.isArray(v1)) {
|
|
78
95
|
conditions.push(v1.some((value) => v2.includes(value.toString())));
|
|
79
96
|
}
|
|
80
|
-
|
|
97
|
+
else {
|
|
81
98
|
conditions.push(v2.includes(v1.toString()));
|
|
82
99
|
}
|
|
83
100
|
break;
|
|
@@ -1,8 +1,23 @@
|
|
|
1
|
+
/* eslint-disable prefer-rest-params */
|
|
1
2
|
function intersect(a, b) {
|
|
2
|
-
|
|
3
|
-
|
|
3
|
+
let aN = [];
|
|
4
|
+
let bN = [];
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
if (Array.isArray(a)) {
|
|
7
|
+
aN = a;
|
|
8
|
+
}
|
|
9
|
+
else if (typeof a === 'string') {
|
|
10
|
+
aN = a.split(',');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (Array.isArray(b)) {
|
|
14
|
+
bN = b;
|
|
15
|
+
}
|
|
16
|
+
else if (typeof b === 'string') {
|
|
17
|
+
bN = b.split(',');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return aN.filter(e => bN.includes(e));
|
|
6
21
|
}
|
|
7
22
|
|
|
8
23
|
/**
|
|
@@ -32,9 +47,11 @@ export default function ifCondOr() {
|
|
|
32
47
|
|
|
33
48
|
switch (operator) {
|
|
34
49
|
case '==':
|
|
50
|
+
// eslint-disable-next-line eqeqeq
|
|
35
51
|
conditions.push(v1 == v2);
|
|
36
52
|
break;
|
|
37
53
|
case '!=':
|
|
54
|
+
// eslint-disable-next-line eqeqeq
|
|
38
55
|
conditions.push(v1 != v2);
|
|
39
56
|
break;
|
|
40
57
|
case '===':
|
|
@@ -78,7 +95,7 @@ export default function ifCondOr() {
|
|
|
78
95
|
if (Array.isArray(v1)) {
|
|
79
96
|
conditions.push(v1.some((value) => v2.includes(value.toString())));
|
|
80
97
|
}
|
|
81
|
-
|
|
98
|
+
else {
|
|
82
99
|
conditions.push(v2.includes(v1.toString()));
|
|
83
100
|
}
|
|
84
101
|
break;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable no-restricted-globals */
|
|
1
2
|
/**
|
|
2
3
|
* Округлення числа до певної точності
|
|
3
4
|
*
|
|
@@ -15,14 +16,14 @@
|
|
|
15
16
|
* @returns {String} Returns HTML
|
|
16
17
|
*/
|
|
17
18
|
export default function round(data, options) {
|
|
18
|
-
const
|
|
19
|
-
if (isNaN(
|
|
19
|
+
const floatData = parseFloat(data);
|
|
20
|
+
if (isNaN(floatData)) return '';
|
|
20
21
|
|
|
21
22
|
const dec = options.hash.dec ? parseInt(options.hash.dec, 10) : 0;
|
|
22
23
|
|
|
23
24
|
if (options.hash.floor) {
|
|
24
|
-
return Math.floor(
|
|
25
|
+
return Math.floor(floatData).toFixed(dec);
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
return
|
|
28
|
+
return floatData.toFixed(dec);
|
|
28
29
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import getPG from '../../plugins/pg/funcs/getPG.js';
|
|
2
|
-
import getSelect from '../../plugins/table/funcs/getSelect.js';
|
|
2
|
+
import getSelect from '../../plugins/table/funcs/getSelect.js';
|
|
3
3
|
|
|
4
4
|
const pg = getPG();
|
|
5
5
|
|
|
@@ -19,7 +19,7 @@ export default async function select(ids, options) {
|
|
|
19
19
|
if (!classifier) return `Не знайдено класифікатор ${data}`;
|
|
20
20
|
|
|
21
21
|
const arr = classifier.arr || [];
|
|
22
|
-
if (classifier.sql && typeof classifier.sql === 'string') {
|
|
22
|
+
if (classifier.sql && typeof classifier.sql === 'string') {
|
|
23
23
|
const metaQuery = `SELECT * FROM (${classifier.sql})q LIMIT 0`;
|
|
24
24
|
const meta = await pg.query(metaQuery);
|
|
25
25
|
const idColumn = meta.fields[0].name;
|
|
@@ -29,18 +29,18 @@ export default async function select(ids, options) {
|
|
|
29
29
|
const values = [idsArray.map(id => String(id))];
|
|
30
30
|
|
|
31
31
|
const { rows } = await pg.query(q, values);
|
|
32
|
-
Object.assign(arr, rows);
|
|
32
|
+
Object.assign(arr, rows);
|
|
33
33
|
}
|
|
34
34
|
if (!arr.length) return idsArray;
|
|
35
35
|
|
|
36
36
|
const results = idsArray.map(id => {
|
|
37
|
-
const result = arr.find(el => String(el.id)
|
|
37
|
+
const result = arr.find(el => String(el.id) === String(id));
|
|
38
38
|
return result ? result.text : '';
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
return results.filter(Boolean).join(', ');
|
|
42
|
-
}
|
|
43
|
-
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
44
|
return `Сталася помилка.<!-- err: ${err.toString()} -->`;
|
|
45
45
|
}
|
|
46
46
|
}
|
package/server/helpers/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable prefer-rest-params */
|
|
1
2
|
import handlebarsSync from 'handlebars';
|
|
2
3
|
import promisedHandlebars from 'promised-handlebars';
|
|
3
4
|
|
|
@@ -54,14 +55,14 @@ function getKeysRecursive(obj, prefix = '') {
|
|
|
54
55
|
const fullKey = prefix ? `${prefix}.${curr}` : curr;
|
|
55
56
|
acc.push(curr);
|
|
56
57
|
if (obj1[curr] && typeof obj1[curr] === 'object' && curr !== 'coordinates') {
|
|
57
|
-
acc
|
|
58
|
+
acc.push(...(getKeysRecursive(obj1[curr], fullKey)));
|
|
58
59
|
}
|
|
59
60
|
return acc;
|
|
60
61
|
}, []);
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
// avoid unhandled exception if helper not registered
|
|
64
|
-
handlebars.registerHelper('helperMissing', function () {
|
|
65
|
+
handlebars.registerHelper('helperMissing', function hm() {
|
|
65
66
|
const options = arguments[arguments.length - 1];
|
|
66
67
|
const args = Array.prototype.slice.call(arguments, 0, arguments.length - 1);
|
|
67
68
|
const keys = getKeysRecursive(options.data?.root);
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
// }
|
|
5
5
|
|
|
6
6
|
const newColor = 'red';
|
|
7
|
-
export default function button(token
|
|
7
|
+
export default function button(token) {
|
|
8
8
|
return `<button onclick="window.v3plugin.$api({ api: '/api/table/${token}', method:'delete',confirm: { title:'Підтвердити операцію', text: 'Ви впевнені що хочете вилучити запис?', cancel: 'Скасувати', confirm : 'Виконати'} })"
|
|
9
9
|
class="group px-2 py-1 inline-flex border-solid justify-center items-center gap-2 rounded-md font-semibold focus:outline-none text-sm transition-all border border-transparent hover:text-white ring-offset-white bg-${newColor}-100 text-${newColor}-100 hover:bg-${newColor}-500 focus:ring-${newColor}-500">
|
|
10
10
|
<svg class="group-hover:fill-white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" width="13" height="13" fill="#ef4444"><path d="M135.2 17.7L128 32 32 32C14.3 32 0 46.3 0 64S14.3 96 32 96l384 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-96 0-7.2-14.3C307.4 6.8 296.3 0 284.2 0L163.8 0c-12.1 0-23.2 6.8-28.6 17.7zM416 128L32 128 53.2 467c1.6 25.3 22.6 45 47.9 45l245.8 0c25.3 0 46.3-19.7 47.9-45L416 128z"/></svg>
|
|
11
11
|
</button>`;
|
|
12
|
-
}
|
|
12
|
+
}
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
// }
|
|
5
5
|
|
|
6
6
|
const newColor = 'blue';
|
|
7
|
-
export default function button(token
|
|
7
|
+
export default function button(token) {
|
|
8
8
|
return `<button onclick="window.v3plugin.$form({ token: '${token}' })"
|
|
9
9
|
class="group px-2 py-1 inline-flex border-solid justify-center items-center gap-2 rounded-md font-semibold focus:outline-none text-sm transition-all border border-transparent hover:text-white ring-offset-white bg-${newColor}-100 text-${newColor}-100 hover:bg-${newColor}-500 focus:ring-${newColor}-500">
|
|
10
10
|
<svg class="group-hover:fill-white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="13" height="13" fill="#3b82f6"><path d="M471.6 21.7c-21.9-21.9-57.3-21.9-79.2 0L362.3 51.7l97.9 97.9 30.1-30.1c21.9-21.9 21.9-57.3 0-79.2L471.6 21.7zm-299.2 220c-6.1 6.1-10.8 13.6-13.5 21.9l-29.6 88.8c-2.9 8.6-.6 18.1 5.8 24.6s15.9 8.7 24.6 5.8l88.8-29.6c8.2-2.7 15.7-7.4 21.9-13.5L437.7 172.3 339.7 74.3 172.4 241.7zM96 64C43 64 0 107 0 160L0 416c0 53 43 96 96 96l256 0c53 0 96-43 96-96l0-96c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 96c0 17.7-14.3 32-32 32L96 448c-17.7 0-32-14.3-32-32l0-256c0-17.7 14.3-32 32-32l96 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L96 64z"/></svg>
|
|
11
11
|
</button>`;
|
|
12
|
-
}
|
|
12
|
+
}
|
|
@@ -21,11 +21,19 @@
|
|
|
21
21
|
export default function coalesce(...args) {
|
|
22
22
|
const options = args.pop();
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
const value = args.find(arg => arg != null && arg !== '');
|
|
25
|
+
|
|
26
|
+
if (value !== undefined) {
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (options.fn) {
|
|
31
|
+
return options.fn(this);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (options.inverse) {
|
|
35
|
+
return options.inverse(this);
|
|
28
36
|
}
|
|
29
37
|
|
|
30
|
-
return
|
|
38
|
+
return '';
|
|
31
39
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint-disable prefer-rest-params */
|
|
2
|
+
export default function paddingNumber(num) {
|
|
2
3
|
const padding = arguments.length === 3 ? arguments[1] : 6;
|
|
3
4
|
return num.toLocaleString('en', { minimumIntegerDigits: padding, useGrouping: false });
|
|
4
|
-
}
|
|
5
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import config from '../../../../config.js';
|
|
2
|
-
|
|
2
|
+
/* eslint-disable no-console */
|
|
3
|
+
// eslint-disable-next-line no-control-regex
|
|
3
4
|
const emailReg = /(?:[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-zA-Z0-9-]*[a-zA-Z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/g;
|
|
4
5
|
|
|
5
6
|
function checkField(key, val, options, idx, body) {
|
|
@@ -57,7 +58,7 @@ function checkBody({ body = {}, arr = [], idx }) {
|
|
|
57
58
|
return acc;
|
|
58
59
|
}, []);
|
|
59
60
|
// acc1.push(result);
|
|
60
|
-
acc1
|
|
61
|
+
acc1.push(...result);
|
|
61
62
|
return acc1;
|
|
62
63
|
}
|
|
63
64
|
|
|
@@ -22,7 +22,7 @@ function getExtraQuery(mainColumns, schema, table, pk) {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
export default async function getFilterSQL({
|
|
25
|
-
table, filter, pg = pgClients.client, search, filterList, query, custom, state, uid, objectId,
|
|
25
|
+
table, filter, pg = pgClients.client, search, filterList, query, custom, state, uid, objectId, order,
|
|
26
26
|
}) {
|
|
27
27
|
if (!table) return { error: 'param table is required', status: 400 };
|
|
28
28
|
|
|
@@ -141,7 +141,7 @@ export default async function getFilterSQL({
|
|
|
141
141
|
body, extraSqlColumns, table, q,
|
|
142
142
|
};
|
|
143
143
|
|
|
144
|
-
const optimizedSQL = `select * from ${getOptimizedQuery(obj)} `;
|
|
144
|
+
const optimizedSQL = `select * from ${getOptimizedQuery(obj)} ${order ? `order by ${order}` : ''}`;
|
|
145
145
|
const tableCount = getOptimizedQuery(obj, true);
|
|
146
146
|
|
|
147
147
|
return {
|
|
@@ -15,7 +15,7 @@ export default function formatValue({
|
|
|
15
15
|
if (filterType === 'text' && value && filter?.columns) {
|
|
16
16
|
const columns = filter.columns.split(',');
|
|
17
17
|
const sval = `ilike '%${decodeURIComponent(value.replace(/%/g, '%25')).replace(/%/g, '\\%')}%'`;
|
|
18
|
-
const query =
|
|
18
|
+
const query = `(${columns.map(el => `"${el}" ${sval}`).join(' or ')})`;
|
|
19
19
|
return { op: '~', query };
|
|
20
20
|
}
|
|
21
21
|
|
|
@@ -65,11 +65,6 @@ export default async function update(req, reply) {
|
|
|
65
65
|
Object.keys(body || {}).filter(key => !Object.keys(schema || {}).includes(key)).forEach(key => delete body[key]);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
if (tokenData?.obj) {
|
|
69
|
-
const objData = tokenData.obj?.split('#').reduce((p, el) => ({ ...p, [el.split('=')[0]]: el.split('=')[1] }), {}) || {};
|
|
70
|
-
Object.assign(body, objData);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
68
|
const xssCheck = checkXSS({ body, schema });
|
|
74
69
|
|
|
75
70
|
if (xssCheck.error && formData?.xssCheck !== false) {
|
|
@@ -89,6 +84,11 @@ export default async function update(req, reply) {
|
|
|
89
84
|
return reply.status(409).send('Дані не пройшли валідацію. Приберіть некоректні дані та спробуйте ще раз');
|
|
90
85
|
}
|
|
91
86
|
|
|
87
|
+
if (tokenData?.obj) {
|
|
88
|
+
const objData = tokenData.obj?.split('#').reduce((p, el) => ({ ...p, [el.split('=')[0]]: el.split('=')[1] }), {}) || {};
|
|
89
|
+
Object.assign(body, objData);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
92
|
const res = await dataUpdate({
|
|
93
93
|
pg,
|
|
94
94
|
table: loadTemplate?.table || table,
|
|
@@ -30,10 +30,10 @@ async function plugin(app, config = {}) {
|
|
|
30
30
|
app.get(`${prefix}/suggest/:data`, {
|
|
31
31
|
config: {
|
|
32
32
|
policy,
|
|
33
|
-
rateLimit: {
|
|
34
|
-
max: 10000,
|
|
35
|
-
timeWindow: '1 minute',
|
|
36
|
-
},
|
|
33
|
+
rateLimit: config.rateLimit ? {
|
|
34
|
+
max: config.rateLimit?.suggest?.max || 10000,
|
|
35
|
+
timeWindow: config.rateLimit?.suggest?.timeWindow || '1 minute',
|
|
36
|
+
} : undefined,
|
|
37
37
|
},
|
|
38
38
|
schema: suggestSchema,
|
|
39
39
|
}, suggest);
|