@opengis/fastify-table 1.4.53 → 1.4.54

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.
Files changed (61) hide show
  1. package/README.md +86 -86
  2. package/package.json +1 -1
  3. package/server/helpers/core/buttonHelper.js +1 -1
  4. package/server/helpers/format/formatAuto.js +13 -13
  5. package/server/helpers/format/formatDate.js +258 -258
  6. package/server/helpers/format/formatDigit.js +21 -21
  7. package/server/helpers/format/formatNum.js +365 -365
  8. package/server/helpers/format/formatNumber.js +55 -55
  9. package/server/helpers/format/formatRelative.js +106 -106
  10. package/server/helpers/format/formatUnit.js +40 -40
  11. package/server/helpers/format/num_format.js +44 -44
  12. package/server/helpers/format/set.js +2 -2
  13. package/server/helpers/funcs/_math.js +50 -50
  14. package/server/helpers/funcs/empty.js +21 -21
  15. package/server/helpers/funcs/ifCond.js +109 -109
  16. package/server/helpers/funcs/ifCondAnd.js +114 -114
  17. package/server/helpers/funcs/ifCondOr.js +115 -115
  18. package/server/helpers/funcs/inc.js +20 -20
  19. package/server/helpers/funcs/json.js +3 -3
  20. package/server/helpers/funcs/qrcode.js +2 -2
  21. package/server/helpers/funcs/round.js +29 -29
  22. package/server/helpers/list/buttonHelper.js +22 -22
  23. package/server/helpers/list/utils/button.js +4 -4
  24. package/server/helpers/string/coalesce.js +39 -39
  25. package/server/helpers/string/concat.js +28 -28
  26. package/server/helpers/string/split.js +20 -20
  27. package/server/helpers/string/str_replace.js +62 -62
  28. package/server/helpers/string/substr.js +32 -32
  29. package/server/helpers/string/translit.js +23 -23
  30. package/server/helpers/string/utils/alphabet.js +76 -76
  31. package/server/helpers/utils/button.js +4 -4
  32. package/server/helpers/utils/buttonAdd.js +1 -1
  33. package/server/helpers/utils/buttonDel.js +1 -1
  34. package/server/helpers/utils/buttonDownload.js +1 -1
  35. package/server/helpers/utils/buttonEdit.js +2 -2
  36. package/server/helpers/utils/buttonPreview.js +1 -1
  37. package/server/helpers/utils/mdToHTML.js +17 -17
  38. package/server/plugins/cron/funcs/interval2ms.js +1 -1
  39. package/server/plugins/cron/index.js +77 -77
  40. package/server/plugins/crud/funcs/getAccess.js +3 -2
  41. package/server/plugins/crud/funcs/setOpt.js +21 -21
  42. package/server/plugins/crud/funcs/setToken.js +43 -43
  43. package/server/plugins/crud/index.js +23 -23
  44. package/server/plugins/hook/index.js +8 -8
  45. package/server/plugins/logger/index.js +33 -33
  46. package/server/plugins/logger/timestampWithTimeZone.js +1 -1
  47. package/server/plugins/migration/index.js +7 -7
  48. package/server/plugins/pg/funcs/getDBParams.js +3 -3
  49. package/server/plugins/policy/sqlInjection.js +34 -34
  50. package/server/plugins/redis/index.js +17 -17
  51. package/server/plugins/table/funcs/customTokens.js +1 -1
  52. package/server/plugins/table/funcs/getFilterSQL/util/getOptimizedQuery.js +2 -2
  53. package/server/plugins/table/funcs/userTokens.js +1 -1
  54. package/server/plugins/util/index.js +7 -7
  55. package/server/plugins/yml/funcs/json2yml.js +1 -1
  56. package/server/plugins/yml/funcs/yml2json.js +2 -2
  57. package/server/routes/file/controllers/export.js +1 -1
  58. package/server/routes/file/controllers/utils/jsonToXls.js +1 -2
  59. package/server/routes/logger/controllers/utils/getRootDir.js +27 -27
  60. package/server/routes/table/controllers/utils/locales.js +1 -1
  61. package/server/routes/util/controllers/status.monitor.js +8 -8
@@ -1,62 +1,62 @@
1
- function replaceLast(str, what, replacement) {
2
- if (!str?.split) return str;
3
- const pcs = str?.split?.(what) || [];
4
- const lastPc = pcs.pop();
5
- return pcs.join(what) + replacement + lastPc;
6
- }
7
-
8
- /**
9
- * Виконує заміну символів у строці. Є можливість заміни регулярного виразу нової строки на тег <br>
10
- *
11
- * @summary Виконання заміни частини строки на значення з останнього аргументу.
12
- * @priority 3
13
- * @type helper
14
- * @alias strReplace
15
- * @tag string
16
- * @example
17
- * {{str_replace 'This Is Alias' ' ' ''}}
18
- * @example
19
- * {{{str_replace '<p>Перший рядок</p><p>Наступний рядок</p>' br=1}}}
20
- * @example
21
- * {{{str_replace 'Перший рядок<br>Наступний рядок' br=1}}}
22
- * @param {Object} br
23
- * @param {Object} newline
24
- * @param {Object} html
25
- * @param {Object} last
26
- * @param {Array} args[0]
27
- * @param {Array} args[1]
28
- * @param {Array} args[2]
29
- * @returns {String} Returns HTML
30
- */
31
-
32
- export default function strReplace(...args) {
33
- const options = args.pop();
34
- const [str, from, to] = args;
35
-
36
- if (!str) return '';
37
-
38
- if (options.hash.br) {
39
- return str.replace(/\n/g, '<br>');
40
- }
41
- if (options.hash.newline) {
42
- return str.replace(/\n/g, '&#10;');
43
- }
44
- if (options.hash.html) {
45
- return str
46
- .replace(/<br>/g, '\n')
47
- .replace(/<\/p>/g, '\n')
48
- .replace(/<\/li>/g, '\n')
49
- .replace(/(<[^>]+>|<[^>]>|<\/[^>]>)/g, '')
50
- .replace(/\n/g, '&#10;');
51
- }
52
-
53
- if (options.hash.last) {
54
- return replaceLast(str, from, to);
55
- }
56
-
57
- if (typeof from !== 'string' || typeof to !== 'string') {
58
- return 'Invalid replacement parameters';
59
- }
60
-
61
- return str.replace(new RegExp(from, 'g'), to);
62
- }
1
+ function replaceLast(str, what, replacement) {
2
+ if (!str?.split) return str;
3
+ const pcs = str?.split?.(what) || [];
4
+ const lastPc = pcs.pop();
5
+ return pcs.join(what) + replacement + lastPc;
6
+ }
7
+
8
+ /**
9
+ * Виконує заміну символів у строці. Є можливість заміни регулярного виразу нової строки на тег <br>
10
+ *
11
+ * @summary Виконання заміни частини строки на значення з останнього аргументу.
12
+ * @priority 3
13
+ * @type helper
14
+ * @alias strReplace
15
+ * @tag string
16
+ * @example
17
+ * {{str_replace 'This Is Alias' ' ' ''}}
18
+ * @example
19
+ * {{{str_replace '<p>Перший рядок</p><p>Наступний рядок</p>' br=1}}}
20
+ * @example
21
+ * {{{str_replace 'Перший рядок<br>Наступний рядок' br=1}}}
22
+ * @param {Object} br
23
+ * @param {Object} newline
24
+ * @param {Object} html
25
+ * @param {Object} last
26
+ * @param {Array} args[0]
27
+ * @param {Array} args[1]
28
+ * @param {Array} args[2]
29
+ * @returns {String} Returns HTML
30
+ */
31
+
32
+ export default function strReplace(...args) {
33
+ const options = args.pop();
34
+ const [str, from, to] = args;
35
+
36
+ if (!str) return '';
37
+
38
+ if (options.hash.br) {
39
+ return str.replace(/\n/g, '<br>');
40
+ }
41
+ if (options.hash.newline) {
42
+ return str.replace(/\n/g, '&#10;');
43
+ }
44
+ if (options.hash.html) {
45
+ return str
46
+ .replace(/<br>/g, '\n')
47
+ .replace(/<\/p>/g, '\n')
48
+ .replace(/<\/li>/g, '\n')
49
+ .replace(/(<[^>]+>|<[^>]>|<\/[^>]>)/g, '')
50
+ .replace(/\n/g, '&#10;');
51
+ }
52
+
53
+ if (options.hash.last) {
54
+ return replaceLast(str, from, to);
55
+ }
56
+
57
+ if (typeof from !== 'string' || typeof to !== 'string') {
58
+ return 'Invalid replacement parameters';
59
+ }
60
+
61
+ return str.replace(new RegExp(from, 'g'), to);
62
+ }
@@ -1,32 +1,32 @@
1
- /**
2
- * Зменшення строки за значеням із змінної. Можна отримати частину строки за першим та останнім символом.
3
- *
4
- * @summary Обрізання строки. За замовчуванням до 100 символів. Є можливість вказання точної кількості.
5
- * @priority 4
6
- * @alias substr
7
- * @tag string
8
- * @type helper
9
- * @example
10
- * {{substr @root.domain from=5}}
11
- * @example
12
- * {{substr req.headers.host max=15}}
13
- * @param {Object} from Число з якого обрізати строку
14
- * @param {Object} max Число до якого обрізати строку
15
- * @param {Object} args[1]] Використовуэться, якщо не дано opt.max
16
- * @param {String|Number} data Строка або число яке обрізається
17
- * @returns {String} Returns HTML
18
- */
19
- export default function substr(data, { hash }) {
20
- const fullString = data ? String(data) : '';
21
-
22
- const max = typeof hash?.max === 'number' ? hash.max : 100;
23
- const from = typeof hash?.from === 'number' ? hash.from : 0;
24
-
25
- const result = fullString.substr(from, max);
26
-
27
- if (hash?.unit && fullString.length > max) {
28
- return `${result}${hash.unit}`;
29
- }
30
-
31
- return result;
32
- }
1
+ /**
2
+ * Зменшення строки за значеням із змінної. Можна отримати частину строки за першим та останнім символом.
3
+ *
4
+ * @summary Обрізання строки. За замовчуванням до 100 символів. Є можливість вказання точної кількості.
5
+ * @priority 4
6
+ * @alias substr
7
+ * @tag string
8
+ * @type helper
9
+ * @example
10
+ * {{substr @root.domain from=5}}
11
+ * @example
12
+ * {{substr req.headers.host max=15}}
13
+ * @param {Object} from Число з якого обрізати строку
14
+ * @param {Object} max Число до якого обрізати строку
15
+ * @param {Object} args[1]] Використовуэться, якщо не дано opt.max
16
+ * @param {String|Number} data Строка або число яке обрізається
17
+ * @returns {String} Returns HTML
18
+ */
19
+ export default function substr(data, { hash }) {
20
+ const fullString = data ? String(data) : '';
21
+
22
+ const max = typeof hash?.max === 'number' ? hash.max : 100;
23
+ const from = typeof hash?.from === 'number' ? hash.from : 0;
24
+
25
+ const result = fullString.substr(from, max);
26
+
27
+ if (hash?.unit && fullString.length > max) {
28
+ return `${result}${hash.unit}`;
29
+ }
30
+
31
+ return result;
32
+ }
@@ -1,23 +1,23 @@
1
- import L from './utils/alphabet.js';
2
-
3
- /**
4
- * Форматування символів з кирилиці на латиницю
5
- *
6
- * @summary Форматування символів з кирилиці на латиницю
7
- * @priority 0
8
- * @deprecated true
9
- * @tag string
10
- * @type helper
11
- * @alias translit
12
- * @example
13
- * {{translit data_name}}
14
- * @param {String} data Перетворення букв з строки з укр на англ
15
- * @returns {String} Returns HTML
16
- */
17
- export default function translit({ data }) {
18
- const rKey = Object.keys(L).join('');
19
-
20
- const reg = new RegExp(`[${rKey}]`, 'g');
21
-
22
- return (data || '').replace(reg, (a) => (a in L ? L[a] : ''));
23
- }
1
+ import L from './utils/alphabet.js';
2
+
3
+ /**
4
+ * Форматування символів з кирилиці на латиницю
5
+ *
6
+ * @summary Форматування символів з кирилиці на латиницю
7
+ * @priority 0
8
+ * @deprecated true
9
+ * @tag string
10
+ * @type helper
11
+ * @alias translit
12
+ * @example
13
+ * {{translit data_name}}
14
+ * @param {String} data Перетворення букв з строки з укр на англ
15
+ * @returns {String} Returns HTML
16
+ */
17
+ export default function translit({ data }) {
18
+ const rKey = Object.keys(L).join('');
19
+
20
+ const reg = new RegExp(`[${rKey}]`, 'g');
21
+
22
+ return (data || '').replace(reg, (a) => (a in L ? L[a] : ''));
23
+ }
@@ -1,76 +1,76 @@
1
- export default {
2
- А: 'A',
3
- а: 'a',
4
- Б: 'B',
5
- б: 'b',
6
- В: 'V',
7
- в: 'v',
8
- Г: 'H',
9
- г: 'h',
10
- Д: 'D',
11
- д: 'd',
12
- Е: 'E',
13
- е: 'e',
14
- Ё: 'Yo',
15
- ё: 'yo',
16
- Ж: 'Zh',
17
- ж: 'zh',
18
- З: 'Z',
19
- з: 'z',
20
- И: 'Y',
21
- и: 'y',
22
- Й: 'Y',
23
- й: 'i',
24
- К: 'K',
25
- к: 'k',
26
- Л: 'L',
27
- л: 'l',
28
- М: 'M',
29
- м: 'm',
30
- Н: 'N',
31
- н: 'n',
32
- О: 'O',
33
- о: 'o',
34
- П: 'P',
35
- п: 'p',
36
- Р: 'R',
37
- р: 'r',
38
- С: 'S',
39
- с: 's',
40
- Т: 'T',
41
- т: 't',
42
- У: 'U',
43
- у: 'u',
44
- Ф: 'F',
45
- ф: 'f',
46
- Х: 'Kh',
47
- х: 'kh',
48
- Ц: 'Ts',
49
- ц: 'ts',
50
- Ч: 'Ch',
51
- ч: 'ch',
52
- Ш: 'Sh',
53
- ш: 'sh',
54
- Щ: 'Shch',
55
- щ: 'shch',
56
- Ъ: '',
57
- ъ: '',
58
- Ы: 'Y',
59
- ы: 'y',
60
- Ь: '',
61
- ь: '',
62
- Э: 'E',
63
- э: 'e',
64
- Ю: 'Yu',
65
- ю: 'yu',
66
- Я: 'Ya',
67
- я: 'ia',
68
- І: 'I',
69
- і: 'i',
70
- Ї: 'Yi',
71
- ї: 'i',
72
- Є: 'Ye',
73
- є: 'ie',
74
- Ґ: 'G',
75
- ґ: 'g',
76
- };
1
+ export default {
2
+ А: 'A',
3
+ а: 'a',
4
+ Б: 'B',
5
+ б: 'b',
6
+ В: 'V',
7
+ в: 'v',
8
+ Г: 'H',
9
+ г: 'h',
10
+ Д: 'D',
11
+ д: 'd',
12
+ Е: 'E',
13
+ е: 'e',
14
+ Ё: 'Yo',
15
+ ё: 'yo',
16
+ Ж: 'Zh',
17
+ ж: 'zh',
18
+ З: 'Z',
19
+ з: 'z',
20
+ И: 'Y',
21
+ и: 'y',
22
+ Й: 'Y',
23
+ й: 'i',
24
+ К: 'K',
25
+ к: 'k',
26
+ Л: 'L',
27
+ л: 'l',
28
+ М: 'M',
29
+ м: 'm',
30
+ Н: 'N',
31
+ н: 'n',
32
+ О: 'O',
33
+ о: 'o',
34
+ П: 'P',
35
+ п: 'p',
36
+ Р: 'R',
37
+ р: 'r',
38
+ С: 'S',
39
+ с: 's',
40
+ Т: 'T',
41
+ т: 't',
42
+ У: 'U',
43
+ у: 'u',
44
+ Ф: 'F',
45
+ ф: 'f',
46
+ Х: 'Kh',
47
+ х: 'kh',
48
+ Ц: 'Ts',
49
+ ц: 'ts',
50
+ Ч: 'Ch',
51
+ ч: 'ch',
52
+ Ш: 'Sh',
53
+ ш: 'sh',
54
+ Щ: 'Shch',
55
+ щ: 'shch',
56
+ Ъ: '',
57
+ ъ: '',
58
+ Ы: 'Y',
59
+ ы: 'y',
60
+ Ь: '',
61
+ ь: '',
62
+ Э: 'E',
63
+ э: 'e',
64
+ Ю: 'Yu',
65
+ ю: 'yu',
66
+ Я: 'Ya',
67
+ я: 'ia',
68
+ І: 'I',
69
+ і: 'i',
70
+ Ї: 'Yi',
71
+ ї: 'i',
72
+ Є: 'Ye',
73
+ є: 'ie',
74
+ Ґ: 'G',
75
+ ґ: 'g',
76
+ };
@@ -1,4 +1,4 @@
1
- export default function button(token, title) {
2
- return `<button onclick="window.v3plugin.$form({ token: '${token}' })"
3
- class="inline-flex items-center px-2 py-1 text-sm font-medium text-white duration-300 bg-blue-600 border border-transparent rounded-lg gap-x-2 hover:bg-blue-700 hover:text-white">${title || 'Редагувати'}</button>`;
4
- }
1
+ export default function button(token, title) {
2
+ return `<button onclick="window.v3plugin.$form({ token: '${token}' })"
3
+ class="inline-flex items-center px-2 py-1 text-sm font-medium text-white duration-300 bg-blue-600 border border-transparent rounded-lg gap-x-2 hover:bg-blue-700 hover:text-white">${title || 'Редагувати'}</button>`;
4
+ }
@@ -2,4 +2,4 @@ const newColor = 'blue';
2
2
  export default function button(token, title) {
3
3
  return `<button onclick="window.v3plugin.$form({ token: '${token}' })"
4
4
  class="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}-500 hover:bg-${newColor}-500 focus:ring-${newColor}-500">${title || 'Додати'}</button>`;
5
- }
5
+ }
@@ -23,4 +23,4 @@ export default function button(token, title, icon) {
23
23
  : `${title || 'Вилучити'}`;
24
24
 
25
25
  return `<button onclick="${apiCall}" class="${buttonClass}">${buttonContent}</button>`;
26
- }
26
+ }
@@ -1,3 +1,3 @@
1
1
  export default function buttonDownload(filepath) {
2
2
  return `<a download=1 class="flex items-center gap-x-2 border py-2 px-3 shadow rounded-xl cursor-pointer w-[42px] y-[34px]" href="${filepath}" target="_blank"><img src="https://cdn.softpro.ua/assets/file-up.svg" alt="generate"></a>`;
3
- }
3
+ }
@@ -13,5 +13,5 @@ export default function button(token, title, icon) {
13
13
  </svg>`
14
14
  : `${title || 'Редагувати'}`;
15
15
 
16
- return `<button onclick="${formCall}" class="${buttonClass}">${buttonContent}</button>`;
17
- }
16
+ return `<button onclick="${formCall}" class="${buttonClass}">${buttonContent}</button>`;
17
+ }
@@ -1,3 +1,3 @@
1
1
  export default function buttonPreview(filepath) {
2
2
  return `<a class="flex items-center gap-x-2 border py-2 px-3 shadow rounded-xl cursor-pointer w-[42px] y-[34px]" href="${filepath}" target="_blank"><img src="https://cdn.softpro.ua/assets/eye.svg" alt="eye"></a>`;
3
- }
3
+ }
@@ -1,17 +1,17 @@
1
- import md from 'markdown-it';
2
-
3
- const md1 = md({ html: true });
4
-
5
- /**
6
- * Перетворення з файла readme.md до формату HTML.
7
- * Потрабно вставити в хелпер шлях до файла або текст readme.md і за допомогою бібліотеки markdown-it перетвориться в HTML.
8
-
9
- * @returns {String} Returns HTML
10
- */
11
- export default function mdToHTML(data) {
12
- // auto detect HTML or MD
13
- // const result = md().render(data);
14
- if (!data) return 'empty data';
15
- const result = md1.render(data);
16
- return result;
17
- }
1
+ import md from 'markdown-it';
2
+
3
+ const md1 = md({ html: true });
4
+
5
+ /**
6
+ * Перетворення з файла readme.md до формату HTML.
7
+ * Потрабно вставити в хелпер шлях до файла або текст readme.md і за допомогою бібліотеки markdown-it перетвориться в HTML.
8
+
9
+ * @returns {String} Returns HTML
10
+ */
11
+ export default function mdToHTML(data) {
12
+ // auto detect HTML or MD
13
+ // const result = md().render(data);
14
+ if (!data) return 'empty data';
15
+ const result = md1.render(data);
16
+ return result;
17
+ }
@@ -37,4 +37,4 @@ const interval2ms = {
37
37
  },
38
38
  };
39
39
 
40
- export default interval2ms;
40
+ export default interval2ms;
@@ -1,77 +1,77 @@
1
- /* eslint-disable no-console */
2
- import { createHash } from 'node:crypto';
3
-
4
- import config from '../../../config.js';
5
-
6
- import getPG from '../pg/funcs/getPG.js';
7
- import pgClients from '../pg/pgClients.js';
8
- import getRedis from '../redis/funcs/getRedis.js';
9
- import logger from '../logger/getLogger.js';
10
- import interval2ms from './funcs/interval2ms.js';
11
-
12
- const rclient = getRedis();
13
-
14
- async function runCron({
15
- pg = pgClients.client, query, name,
16
- }) {
17
- const db = pg?.options?.database;
18
-
19
- // verifyUnique
20
- const key = `cron:unique:${name}`;
21
- const unique = config.redis ? await rclient.setnx(key, 1) : null;
22
- const ttl = config.redis ? await rclient.ttl(key) : -1;
23
-
24
- if (!unique && ttl !== -1) {
25
- // if (config.trace) console.log(name, db, query, 'skip unique');
26
- return;
27
- }
28
-
29
- if (config.redis) {
30
- await rclient.expire(key, 20);
31
- }
32
-
33
- try {
34
- if (!pg.pk && config.pg) { await pg.init(); }
35
-
36
- if (config.trace) console.time(`${db}:${query}`);
37
- const { command, rows = [], rowCount } = pg?.pk ? await pg.query(query) : {};
38
- if (config.trace) console.timeEnd(`${db}:${query}`);
39
-
40
- logger.file('cron', { db, name, result: { command, rows, rowCount } });
41
- }
42
- catch (err) {
43
- if (config.trace) console.error(name, err.toString());
44
- logger.file('cron/error', { db, name, error: err.toString() });
45
- logger.error(err);
46
- }
47
- }
48
-
49
- async function plugin() {
50
- if (config.cronList?.length) {
51
- config.cronList?.filter?.(el => el.query && !el.disabled)?.forEach?.((el, idx) => {
52
- const { interval, db, query } = el;
53
- const name = createHash('md5').update(`${config.port || 3000}:${db}:${query}`).digest('hex');
54
- const pg = getPG(db);
55
-
56
- if (config.trace) console.log('cron-list: init', db, idx);
57
-
58
- const [waitMs, intervalMs] = interval2ms[typeof interval](interval);
59
-
60
- if (intervalMs < 1000) {
61
- if (config.trace) console.error('cron-list: skip too small interval', db, idx);
62
- logger.file('cron', { name, error: `interval ${interval} too small` });
63
- return;
64
- }
65
-
66
- // setTimeout to w8 for the time to start
67
- setTimeout(() => {
68
- runCron({ pg, query, name });
69
- // interval
70
- setInterval(() => {
71
- runCron({ pg, query, name });
72
- }, intervalMs);
73
- }, waitMs);
74
- });
75
- }
76
- }
77
- export default plugin;
1
+ /* eslint-disable no-console */
2
+ import { createHash } from 'node:crypto';
3
+
4
+ import config from '../../../config.js';
5
+
6
+ import getPG from '../pg/funcs/getPG.js';
7
+ import pgClients from '../pg/pgClients.js';
8
+ import getRedis from '../redis/funcs/getRedis.js';
9
+ import logger from '../logger/getLogger.js';
10
+ import interval2ms from './funcs/interval2ms.js';
11
+
12
+ const rclient = getRedis();
13
+
14
+ async function runCron({
15
+ pg = pgClients.client, query, name,
16
+ }) {
17
+ const db = pg?.options?.database;
18
+
19
+ // verifyUnique
20
+ const key = `cron:unique:${name}`;
21
+ const unique = config.redis ? await rclient.setnx(key, 1) : null;
22
+ const ttl = config.redis ? await rclient.ttl(key) : -1;
23
+
24
+ if (!unique && ttl !== -1) {
25
+ // if (config.trace) console.log(name, db, query, 'skip unique');
26
+ return;
27
+ }
28
+
29
+ if (config.redis) {
30
+ await rclient.expire(key, 20);
31
+ }
32
+
33
+ try {
34
+ if (!pg.pk && config.pg) { await pg.init(); }
35
+
36
+ if (config.trace) console.time(`${db}:${query}`);
37
+ const { command, rows = [], rowCount } = pg?.pk ? await pg.query(query) : {};
38
+ if (config.trace) console.timeEnd(`${db}:${query}`);
39
+
40
+ logger.file('cron', { db, name, result: { command, rows, rowCount } });
41
+ }
42
+ catch (err) {
43
+ if (config.trace) console.error(name, err.toString());
44
+ logger.file('cron/error', { db, name, error: err.toString() });
45
+ logger.error(err);
46
+ }
47
+ }
48
+
49
+ async function plugin() {
50
+ if (config.cronList?.length) {
51
+ config.cronList?.filter?.(el => el.query && !el.disabled)?.forEach?.((el, idx) => {
52
+ const { interval, db, query } = el;
53
+ const name = createHash('md5').update(`${config.port || 3000}:${db}:${query}`).digest('hex');
54
+ const pg = getPG(db);
55
+
56
+ if (config.trace) console.log('cron-list: init', db, idx);
57
+
58
+ const [waitMs, intervalMs] = interval2ms[typeof interval](interval);
59
+
60
+ if (intervalMs < 1000) {
61
+ if (config.trace) console.error('cron-list: skip too small interval', db, idx);
62
+ logger.file('cron', { name, error: `interval ${interval} too small` });
63
+ return;
64
+ }
65
+
66
+ // setTimeout to w8 for the time to start
67
+ setTimeout(() => {
68
+ runCron({ pg, query, name });
69
+ // interval
70
+ setInterval(() => {
71
+ runCron({ pg, query, name });
72
+ }, intervalMs);
73
+ }, waitMs);
74
+ });
75
+ }
76
+ }
77
+ export default plugin;
@@ -76,14 +76,15 @@ export default async function getAccess({ table, form, user = {} }, pg = pgClien
76
76
  ...el.rows[0] || {},
77
77
  roles: el.rows?.map?.(row => row.role_id) || [],
78
78
  actions: el.rows?.map?.(row => row.actions).flat() || [],
79
+ interface_actions: el.rows?.map?.(row => row.interface_actions).flat() || [],
79
80
  }))
80
81
  : {};
81
82
 
82
83
  const query = userAccess?.scope === 'my' ? `uid='${uid}'` : '1=1';
83
84
  const actions = userAccess?.interface_actions
84
- ?.filter?.((el, idx, arr) => arr.indexOf(el) === idx)
85
85
  ?.filter(el => (userAccess?.role_actions?.length ? userAccess?.role_actions.includes(el) : true))
86
- ?.filter(el => tableActions.includes(el));
86
+ ?.filter(el => tableActions.includes(el))
87
+ ?.filter?.((el, idx, arr) => arr.indexOf(el) === idx);
87
88
  return {
88
89
  scope: userAccess?.scope,
89
90
  roles: userAccess?.roles,