@opengis/fastify-table 1.1.51 → 1.1.52

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 (218) hide show
  1. package/.eslintrc.cjs +42 -42
  2. package/.gitlab-ci.yml +18 -18
  3. package/Changelog.md +352 -352
  4. package/README.md +26 -26
  5. package/config.js +10 -10
  6. package/cron/controllers/cronApi.js +22 -22
  7. package/cron/controllers/utils/cronList.js +1 -1
  8. package/cron/funcs/addCron.js +132 -132
  9. package/cron/index.js +12 -10
  10. package/cron/schema.js +8 -0
  11. package/crud/controllers/deleteCrud.js +36 -36
  12. package/crud/controllers/insert.js +71 -71
  13. package/crud/controllers/update.js +76 -76
  14. package/crud/controllers/utils/xssInjection.js +72 -72
  15. package/crud/funcs/dataDelete.js +19 -19
  16. package/crud/funcs/dataInsert.js +30 -30
  17. package/crud/funcs/dataUpdate.js +48 -48
  18. package/crud/funcs/getAccess.js +46 -46
  19. package/crud/funcs/getOpt.js +10 -10
  20. package/crud/funcs/getToken.js +27 -27
  21. package/crud/funcs/isFileExists.js +13 -13
  22. package/crud/funcs/setOpt.js +16 -16
  23. package/crud/funcs/setToken.js +53 -53
  24. package/crud/funcs/utils/getFolder.js +9 -9
  25. package/crud/funcs/utils/logChanges.js +62 -62
  26. package/crud/index.js +31 -36
  27. package/crud/schema.js +11 -0
  28. package/docs/.vitepress/abbr.mjs +26 -26
  29. package/docs/.vitepress/config.mjs +127 -127
  30. package/docs/.vitepress/navigation.mjs +82 -82
  31. package/docs/.vitepress/theme/Layout.vue +17 -17
  32. package/docs/.vitepress/theme/components/NavigationLinks.vue +102 -102
  33. package/docs/.vitepress/theme/components/Panzoom.vue +169 -169
  34. package/docs/.vitepress/theme/index.mjs +15 -15
  35. package/docs/.vitepress/theme/style.scss +163 -163
  36. package/docs/abbr.json +4 -4
  37. package/docs/api/cron/cronApi.md +56 -56
  38. package/docs/api/crud/deleteCrud.md +58 -58
  39. package/docs/api/crud/insert.md +82 -82
  40. package/docs/api/crud/update.md +85 -85
  41. package/docs/api/index.md +47 -47
  42. package/docs/api/notification/testEmail.md +91 -91
  43. package/docs/api/table/card.md +73 -73
  44. package/docs/api/table/data.md +134 -134
  45. package/docs/api/table/export.md +60 -60
  46. package/docs/api/table/filter.md +104 -104
  47. package/docs/api/table/form.md +126 -126
  48. package/docs/api/table/search.md +123 -123
  49. package/docs/api/table/suggest.md +156 -156
  50. package/docs/api/table/table.md +107 -107
  51. package/docs/api/user/user.cls.id.md +77 -77
  52. package/docs/api/user/user.cls.md +49 -49
  53. package/docs/api/user/user.cls.post.md +62 -62
  54. package/docs/api/user/user.info.md +37 -37
  55. package/docs/api/utils/logger.file.md +60 -60
  56. package/docs/api/utils/next.id.md +34 -34
  57. package/docs/api/utils/properties.add.md +127 -127
  58. package/docs/api/utils/properties.get.md +73 -73
  59. package/docs/api/utils/status.monitor.md +36 -36
  60. package/docs/api/widget/widget.del.md +76 -76
  61. package/docs/api/widget/widget.get.md +233 -233
  62. package/docs/api/widget/widget.set.md +88 -88
  63. package/docs/db/admin.md +947 -947
  64. package/docs/db/crm.md +564 -564
  65. package/docs/db/index.md +9 -9
  66. package/docs/db/log.md +204 -204
  67. package/docs/hook/card/afterCard.md +20 -20
  68. package/docs/hook/card/preCard.md +25 -25
  69. package/docs/hook/data/afterData.md +26 -26
  70. package/docs/hook/data/preData.md +26 -26
  71. package/docs/hook/deleteCrud/afterDelete.md +21 -21
  72. package/docs/hook/deleteCrud/preDelete.md +26 -26
  73. package/docs/hook/form/afterForm.md +19 -19
  74. package/docs/hook/form/preForm.md +26 -26
  75. package/docs/hook/getTemplate/afterTemplate.md +24 -24
  76. package/docs/hook/getTemplate/preTemplate.md +29 -29
  77. package/docs/hook/index.md +45 -45
  78. package/docs/hook/insert/afterInsert.md +41 -41
  79. package/docs/hook/insert/preInsert.md +25 -25
  80. package/docs/hook/table/afterTable.md +20 -20
  81. package/docs/hook/table/preTable.md +25 -25
  82. package/docs/hook/update/afterUpdate.md +41 -41
  83. package/docs/hook/update/preUpdate.md +25 -25
  84. package/docs/index.md +42 -42
  85. package/docs/public/fastify-dark.svg +3 -3
  86. package/docs/public/logo-short-dark.svg +11 -11
  87. package/docs/public/logo-short.svg +10 -10
  88. package/docs/public/logo.svg +19 -19
  89. package/docs/readme/index.md +121 -121
  90. package/docs/templates/card.md +83 -83
  91. package/docs/templates/cls.md +29 -29
  92. package/docs/templates/filters.md +91 -91
  93. package/docs/templates/forms.md +139 -139
  94. package/docs/templates/index.md +28 -28
  95. package/docs/templates/select.md +90 -90
  96. package/docs/templates/table.md +162 -162
  97. package/docs/utils/cron/addCron.md +29 -29
  98. package/docs/utils/crud/dataInsert.md +51 -51
  99. package/docs/utils/crud/dataUpdate.md +52 -52
  100. package/docs/utils/crud/getOpt.md +33 -33
  101. package/docs/utils/crud/isFileExists.md +37 -37
  102. package/docs/utils/crud/setOpt.md +37 -37
  103. package/docs/utils/hook/addHook.md +74 -74
  104. package/docs/utils/hook/applyHook.md +64 -64
  105. package/docs/utils/index.md +47 -47
  106. package/docs/utils/notification/addNotification.md +28 -28
  107. package/docs/utils/notification/notification.md +41 -41
  108. package/docs/utils/pg/autoIndex.md +22 -22
  109. package/docs/utils/pg/getMeta.md +58 -58
  110. package/docs/utils/pg/getPG.md +34 -34
  111. package/docs/utils/pg/init.md +29 -29
  112. package/docs/utils/pg/pg.md +70 -70
  113. package/docs/utils/redis/getRedis.md +36 -36
  114. package/docs/utils/redis/rclient.md +74 -74
  115. package/docs/utils/table/getForm.md +68 -68
  116. package/docs/utils/table/getMeta.md +55 -55
  117. package/docs/utils/table/getSelect.md +38 -38
  118. package/docs/utils/table/getSelectMeta.md +46 -46
  119. package/docs/utils/table/getTable.md +77 -77
  120. package/helper.js +30 -30
  121. package/index.js +105 -105
  122. package/migration/exec.migrations.js +79 -79
  123. package/module/core/select/core.user_mentioned.sql +1 -1
  124. package/module/test/cls/itree.composition.json +25 -25
  125. package/module/test/table/test.rest_zone.table.json +265 -265
  126. package/notification/controllers/readNotifications.js +27 -30
  127. package/notification/controllers/testEmail.js +46 -50
  128. package/notification/controllers/userNotifications.js +61 -64
  129. package/notification/funcs/addNotification.js +21 -21
  130. package/notification/funcs/sendNotification.js +112 -112
  131. package/notification/index.js +3 -8
  132. package/notification/schema.js +10 -0
  133. package/package.json +41 -41
  134. package/pg/funcs/getMeta.js +29 -29
  135. package/pg/funcs/getPG.js +30 -30
  136. package/pg/pgClients.js +20 -20
  137. package/policy/funcs/checkPolicy.js +92 -92
  138. package/policy/funcs/sqlInjection.js +33 -33
  139. package/policy/index.js +14 -14
  140. package/redis/client.js +8 -8
  141. package/redis/funcs/getRedis.js +23 -23
  142. package/redis/funcs/redisClients.js +2 -2
  143. package/redis/index.js +19 -19
  144. package/server/migrations/0.sql +78 -78
  145. package/server/migrations/cls.sql +39 -39
  146. package/server/migrations/log.sql +80 -80
  147. package/server/migrations/properties.sql +144 -144
  148. package/server/migrations/roles.sql +172 -172
  149. package/server/migrations/users.sql +168 -168
  150. package/server.js +26 -26
  151. package/table/controllers/data.js +157 -150
  152. package/table/controllers/filter.js +61 -50
  153. package/table/controllers/form.js +42 -42
  154. package/table/controllers/search.js +76 -80
  155. package/table/controllers/suggest.js +79 -79
  156. package/table/controllers/table.js +83 -83
  157. package/table/controllers/utils/addTemplateDir.js +8 -8
  158. package/table/controllers/utils/getSelect.js +19 -19
  159. package/table/controllers/utils/getSelectMeta.js +66 -66
  160. package/table/controllers/utils/getTemplate_old.js +28 -28
  161. package/table/controllers/utils/getTemplates.js +18 -18
  162. package/table/controllers/utils/gisIRColumn.js +72 -67
  163. package/table/controllers/utils/loadTemplate.js +1 -1
  164. package/table/controllers/utils/loadTemplatePath.js +1 -1
  165. package/table/controllers/utils/userTemplateDir.js +1 -1
  166. package/table/funcs/getFilterSQL/index.js +94 -94
  167. package/table/funcs/getFilterSQL/util/formatValue.js +170 -170
  168. package/table/funcs/getFilterSQL/util/getCustomQuery.js +13 -13
  169. package/table/funcs/getFilterSQL/util/getFilterQuery.js +66 -66
  170. package/table/funcs/getFilterSQL/util/getOptimizedQuery.js +12 -12
  171. package/table/funcs/getFilterSQL/util/getTableSql.js +34 -34
  172. package/table/funcs/metaFormat/getSelectVal.js +21 -21
  173. package/table/funcs/metaFormat/index.js +28 -28
  174. package/table/index.js +37 -37
  175. package/table/schema.js +64 -54
  176. package/test/api/applyHook.test.js +95 -95
  177. package/test/api/crud.test.js +89 -89
  178. package/test/api/crud.xss.test.js +80 -80
  179. package/test/api/suggest.test.js +66 -66
  180. package/test/api/table.test.js +134 -134
  181. package/test/api/user.test.js +85 -85
  182. package/test/api/widget.test.js +117 -117
  183. package/test/config.example +18 -18
  184. package/test/funcs/pg.test.js +34 -34
  185. package/test/funcs/redis.test.js +19 -19
  186. package/test/helper/formatDate.test.js +62 -62
  187. package/test/templates/cls/test.json +9 -9
  188. package/test/templates/form/cp_building.form.json +32 -32
  189. package/test/templates/select/account_id.json +3 -3
  190. package/test/templates/select/storage.data.json +2 -2
  191. package/test/templates/select/test.storage.data.json +3 -3
  192. package/test/templates/select/test.suggest.ato_new.json +3 -3
  193. package/test/templates/select/test.suggest.ato_new.sql +25 -25
  194. package/test/templates/select/test.suggest.data.json +4 -4
  195. package/test/templates/select/test.suggest.parent.sql +1 -1
  196. package/test/templates/table/gis.dataset.table.json +20 -20
  197. package/user/controllers/user.cls.id.js +14 -14
  198. package/user/controllers/user.cls.js +71 -75
  199. package/user/controllers/user.cls.post.js +52 -55
  200. package/user/controllers/user.info.js +17 -21
  201. package/user/index.js +7 -36
  202. package/user/schema.js +17 -0
  203. package/util/controllers/logger.file.js +91 -91
  204. package/util/controllers/next.id.js +4 -4
  205. package/util/controllers/properties.add.js +56 -60
  206. package/util/controllers/properties.get.js +16 -19
  207. package/util/controllers/status.monitor.js +8 -8
  208. package/util/controllers/utils/checkUserAccess.js +20 -17
  209. package/util/controllers/utils/getRootDir.js +25 -25
  210. package/util/index.js +19 -23
  211. package/util/schema.js +19 -0
  212. package/utils.js +106 -104
  213. package/widget/controllers/utils/historyFormat.js +76 -76
  214. package/widget/controllers/utils/obj2db.js +13 -13
  215. package/widget/controllers/widget.del.js +41 -44
  216. package/widget/controllers/widget.get.js +96 -102
  217. package/widget/controllers/widget.set.js +74 -79
  218. package/widget/index.js +40 -40
package/README.md CHANGED
@@ -1,26 +1,26 @@
1
- # fastify-table
2
-
3
- [![NPM version](https://img.shields.io/npm/v/@opengis/fastify-table)](https://www.npmjs.com/package/@opengis/fastify-table)
4
- [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](http://standardjs.com/)
5
-
6
- It standardizes the entire form building process, while taking care of everything from rendering to validation and processing:
7
-
8
- - pg
9
- - redis
10
- - crud
11
-
12
- ## Install
13
-
14
- ```bash
15
- npm i @opengis/fastify-table
16
- ```
17
-
18
- ## Usage
19
-
20
- ```js
21
- fastify.register(import('@opengis/fastify-table'), config);
22
- ```
23
-
24
- ## Documenation
25
-
26
- For a detailed understanding fastify-table, its features, and how to use them, refer to our [Documentation](https://apidocs.softpro.ua/gis.storage/).
1
+ # fastify-table
2
+
3
+ [![NPM version](https://img.shields.io/npm/v/@opengis/fastify-table)](https://www.npmjs.com/package/@opengis/fastify-table)
4
+ [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](http://standardjs.com/)
5
+
6
+ It standardizes the entire form building process, while taking care of everything from rendering to validation and processing:
7
+
8
+ - pg
9
+ - redis
10
+ - crud
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ npm i @opengis/fastify-table
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ```js
21
+ fastify.register(import('@opengis/fastify-table'), config);
22
+ ```
23
+
24
+ ## Documenation
25
+
26
+ For a detailed understanding fastify-table, its features, and how to use them, refer to our [Documentation](https://apidocs.softpro.ua/gis.storage/).
package/config.js CHANGED
@@ -1,10 +1,10 @@
1
- import fs from 'fs';
2
-
3
- const fileName = ['config.json', '/data/local/config.json'].find(el => (fs.existsSync(el) ? el : null));
4
- const config = fileName ? JSON.parse(fs.readFileSync(fileName)) : {};
5
-
6
- Object.assign(config, {
7
- allTemplates: config?.allTemplates || {},
8
- });
9
-
10
- export default config;
1
+ import fs from 'fs';
2
+
3
+ const fileName = ['config.json', '/data/local/config.json'].find(el => (fs.existsSync(el) ? el : null));
4
+ const config = fileName ? JSON.parse(fs.readFileSync(fileName)) : {};
5
+
6
+ Object.assign(config, {
7
+ allTemplates: config?.allTemplates || {},
8
+ });
9
+
10
+ export default config;
@@ -1,22 +1,22 @@
1
- import cronList from './utils/cronList.js';
2
-
3
- export default async function cronApi(req) {
4
- const {
5
- params = {}, user = {}, hostname,
6
- } = req;
7
-
8
- if ((!user.uid || !user.user_type?.includes('admin')) && !hostname?.includes('localhost')) {
9
- return { message: 'access restricted', status: 403 };
10
- }
11
-
12
- if (params.name === 'list') {
13
- return { data: Object.keys(cronList || {}) };
14
- }
15
-
16
- if (!cronList[params.name]) {
17
- return { message: `cron not found: ${params.name}`, status: 404 };
18
- }
19
-
20
- const result = await cronList[params.name](req);
21
- return result;
22
- }
1
+ import cronList from './utils/cronList.js';
2
+
3
+ export default async function cronApi(req) {
4
+ const {
5
+ params = {}, user = {}, hostname,
6
+ } = req;
7
+
8
+ if ((!user.uid || !user.user_type?.includes('admin')) && !hostname?.includes('localhost')) {
9
+ return { message: 'access restricted', status: 403 };
10
+ }
11
+
12
+ if (params.name === 'list') {
13
+ return { data: Object.keys(cronList || {}) };
14
+ }
15
+
16
+ if (!cronList[params.name]) {
17
+ return { message: `cron not found: ${params.name}`, status: 404 };
18
+ }
19
+
20
+ const result = await cronList[params.name](req);
21
+ return result;
22
+ }
@@ -1 +1 @@
1
- export default {};
1
+ export default {};
@@ -1,132 +1,132 @@
1
- import { createHash } from 'crypto';
2
-
3
- import cronList from '../controllers/utils/cronList.js';
4
- import getRedis from '../../redis/funcs/getRedis.js';
5
- import getPG from '../../pg/funcs/getPG.js';
6
- import config from '../../config.js';
7
-
8
- const md5 = (string) => createHash('md5').update(string).digest('hex');
9
-
10
- async function verifyUnique(name, rclient) {
11
- const cronId = config.port || 3000 + md5(name);
12
- // one per node check
13
- const key = `cron:unique:${cronId}`;
14
- const unique = await rclient.setnx(key, 1);
15
- const ttl = await rclient.ttl(key);
16
- if (!unique && ttl !== -1) {
17
- return false;
18
- }
19
- await rclient.expire(key, 20);
20
- return true;
21
- }
22
-
23
- const intervalStringMs = {
24
- everyMin: 1000 * 60,
25
- tenMin: 1000 * 60 * 10,
26
- everyHour: 1000 * 60 * 60,
27
- isHalfday: 1000 * 60 * 60 * 12,
28
- dailyHour: 1000 * 60 * 60 * 24,
29
- };
30
-
31
- const interval2ms = {
32
- string: (interval) => {
33
- const date = new Date();
34
- const intervarSplit = interval.match(/^(\*{2}|(\*)?(\d{1,2})):(\*(\d)|(\d{2}))/);
35
- if (!intervarSplit) {
36
- throw new Error(`interval ${interval} not suported`);
37
- }
38
- const [, , isHalfday, dailyHour, , tenMin, HourlyMin] = intervarSplit;
39
- const intervalMs = (isHalfday && intervalStringMs.isHalfday)
40
- || (dailyHour && intervalStringMs.dailyHour)
41
- || (tenMin && intervalStringMs.tenMin)
42
- || intervalStringMs.everyHour;
43
- const offsetDay = ((+dailyHour || 0) * 60 + (+tenMin || +HourlyMin)) * 60 * 1000;
44
- const offsetCur = (date - date.getTimezoneOffset() * 1000 * 60) % intervalMs;
45
- const waitMs = (offsetDay - offsetCur + intervalMs) % intervalMs;
46
- return [waitMs, intervalMs];
47
- },
48
- number: (interval) => {
49
- const date = new Date();
50
- const intervalMs = interval * 1000;
51
- const dateWithTZ = date - date.getTimezoneOffset() * 1000 * 60;
52
- const offsetCur = dateWithTZ % intervalMs;
53
- // start every cron within 1 hour
54
- const sixtyMinutesStartMs = 3600000;
55
- const waitMs = (intervalMs - offsetCur) % sixtyMinutesStartMs;
56
- return [waitMs, intervalMs];
57
- },
58
- };
59
-
60
- async function runCron({
61
- pg, funcs, func, name, rclient, log,
62
- }) {
63
- const unique = await verifyUnique(name, rclient);
64
-
65
- if (!unique) return;
66
- const db = pg.options.database;
67
- log.debug(`cron.${name}`, 1, db);
68
- try {
69
- const data = await func({ pg, funcs, log });
70
- log.debug('cron', { db, name, result: data });
71
- log.info('cron', { db, name, result: data });
72
- }
73
- catch (err) {
74
- log.debug('cron', { db, name, error: err.toString() });
75
- log.error('cron', { db, name, error: err.toString() });
76
- }
77
- }
78
-
79
- /**
80
- * interval:
81
- * - 02:54 - every day
82
- * - 2:03 - every day
83
- * - *1:43 - 2 times a day
84
- * - *12:03 - 2 times a day
85
- * - **:54 - every hour
86
- * - **:*3 - every 10 minutes
87
- * - 60 - every minute
88
- * - 10 * 60 - every 10 minutes
89
- */
90
-
91
- export default async function addCron(func, interval, fastify) {
92
- if (!fastify) {
93
- throw new Error('not enough params: fastify');
94
- }
95
-
96
- const { log } = fastify;
97
- const { time = {}, disabled = [] } = config.cron || {};
98
- const pg = getPG();
99
- const rclient = getRedis();
100
-
101
- const name = func.name || func.toString().split('/').at(-1).split('\'')[0];
102
-
103
- // if (!config.isServer) return;
104
-
105
- if (disabled.includes(name)) {
106
- log.debug('cron', { name, message: 'cron disabled' });
107
- return;
108
- }
109
-
110
- cronList[name] = func;
111
-
112
- const userInterval = time[name] || interval;
113
- const [waitMs, intervalMs] = interval2ms[typeof interval](userInterval);
114
-
115
- if (intervalMs < 1000) {
116
- log.warn('cron', { name, error: `interval ${interval} to small` });
117
- return;
118
- }
119
-
120
- // setTimeout to w8 for the time to start
121
- setTimeout(() => {
122
- runCron({
123
- pg, funcs: fastify, func, name, rclient, log,
124
- });
125
- // interval
126
- setInterval(() => {
127
- runCron({
128
- pg, funcs: fastify, func, name, rclient, log,
129
- });
130
- }, intervalMs);
131
- }, waitMs);
132
- }
1
+ import { createHash } from 'crypto';
2
+
3
+ import cronList from '../controllers/utils/cronList.js';
4
+ import getRedis from '../../redis/funcs/getRedis.js';
5
+ import getPG from '../../pg/funcs/getPG.js';
6
+ import config from '../../config.js';
7
+
8
+ const md5 = (string) => createHash('md5').update(string).digest('hex');
9
+
10
+ async function verifyUnique(name, rclient) {
11
+ const cronId = config.port || 3000 + md5(name);
12
+ // one per node check
13
+ const key = `cron:unique:${cronId}`;
14
+ const unique = await rclient.setnx(key, 1);
15
+ const ttl = await rclient.ttl(key);
16
+ if (!unique && ttl !== -1) {
17
+ return false;
18
+ }
19
+ await rclient.expire(key, 20);
20
+ return true;
21
+ }
22
+
23
+ const intervalStringMs = {
24
+ everyMin: 1000 * 60,
25
+ tenMin: 1000 * 60 * 10,
26
+ everyHour: 1000 * 60 * 60,
27
+ isHalfday: 1000 * 60 * 60 * 12,
28
+ dailyHour: 1000 * 60 * 60 * 24,
29
+ };
30
+
31
+ const interval2ms = {
32
+ string: (interval) => {
33
+ const date = new Date();
34
+ const intervarSplit = interval.match(/^(\*{2}|(\*)?(\d{1,2})):(\*(\d)|(\d{2}))/);
35
+ if (!intervarSplit) {
36
+ throw new Error(`interval ${interval} not suported`);
37
+ }
38
+ const [, , isHalfday, dailyHour, , tenMin, HourlyMin] = intervarSplit;
39
+ const intervalMs = (isHalfday && intervalStringMs.isHalfday)
40
+ || (dailyHour && intervalStringMs.dailyHour)
41
+ || (tenMin && intervalStringMs.tenMin)
42
+ || intervalStringMs.everyHour;
43
+ const offsetDay = ((+dailyHour || 0) * 60 + (+tenMin || +HourlyMin)) * 60 * 1000;
44
+ const offsetCur = (date - date.getTimezoneOffset() * 1000 * 60) % intervalMs;
45
+ const waitMs = (offsetDay - offsetCur + intervalMs) % intervalMs;
46
+ return [waitMs, intervalMs];
47
+ },
48
+ number: (interval) => {
49
+ const date = new Date();
50
+ const intervalMs = interval * 1000;
51
+ const dateWithTZ = date - date.getTimezoneOffset() * 1000 * 60;
52
+ const offsetCur = dateWithTZ % intervalMs;
53
+ // start every cron within 1 hour
54
+ const sixtyMinutesStartMs = 3600000;
55
+ const waitMs = (intervalMs - offsetCur) % sixtyMinutesStartMs;
56
+ return [waitMs, intervalMs];
57
+ },
58
+ };
59
+
60
+ async function runCron({
61
+ pg, funcs, func, name, rclient, log,
62
+ }) {
63
+ const unique = await verifyUnique(name, rclient);
64
+
65
+ if (!unique) return;
66
+ const db = pg.options.database;
67
+ log.debug(`cron.${name}`, 1, db);
68
+ try {
69
+ const data = await func({ pg, funcs, log });
70
+ log.debug('cron', { db, name, result: data });
71
+ log.info('cron', { db, name, result: data });
72
+ }
73
+ catch (err) {
74
+ log.debug('cron', { db, name, error: err.toString() });
75
+ log.error('cron', { db, name, error: err.toString() });
76
+ }
77
+ }
78
+
79
+ /**
80
+ * interval:
81
+ * - 02:54 - every day
82
+ * - 2:03 - every day
83
+ * - *1:43 - 2 times a day
84
+ * - *12:03 - 2 times a day
85
+ * - **:54 - every hour
86
+ * - **:*3 - every 10 minutes
87
+ * - 60 - every minute
88
+ * - 10 * 60 - every 10 minutes
89
+ */
90
+
91
+ export default async function addCron(func, interval, fastify) {
92
+ if (!fastify) {
93
+ throw new Error('not enough params: fastify');
94
+ }
95
+
96
+ const { log } = fastify;
97
+ const { time = {}, disabled = [] } = config.cron || {};
98
+ const pg = getPG();
99
+ const rclient = getRedis();
100
+
101
+ const name = func.name || func.toString().split('/').at(-1).split('\'')[0];
102
+
103
+ // if (!config.isServer) return;
104
+
105
+ if (disabled.includes(name)) {
106
+ log.debug('cron', { name, message: 'cron disabled' });
107
+ return;
108
+ }
109
+
110
+ cronList[name] = func;
111
+
112
+ const userInterval = time[name] || interval;
113
+ const [waitMs, intervalMs] = interval2ms[typeof interval](userInterval);
114
+
115
+ if (intervalMs < 1000) {
116
+ log.warn('cron', { name, error: `interval ${interval} to small` });
117
+ return;
118
+ }
119
+
120
+ // setTimeout to w8 for the time to start
121
+ setTimeout(() => {
122
+ runCron({
123
+ pg, funcs: fastify, func, name, rclient, log,
124
+ });
125
+ // interval
126
+ setInterval(() => {
127
+ runCron({
128
+ pg, funcs: fastify, func, name, rclient, log,
129
+ });
130
+ }, intervalMs);
131
+ }, waitMs);
132
+ }
package/cron/index.js CHANGED
@@ -1,10 +1,12 @@
1
- import cronApi from './controllers/cronApi.js';
2
- import addCron from './funcs/addCron.js';
3
-
4
- async function plugin(fastify, config = {}) {
5
- const prefix = config.prefix || '/api';
6
- fastify.decorate('addCron', addCron);
7
- fastify.get(`${prefix}/cron/:name`, {}, cronApi);
8
- }
9
-
10
- export default plugin;
1
+ import cronApi from './controllers/cronApi.js';
2
+ import addCron from './funcs/addCron.js';
3
+
4
+ import { cronSchema } from './schema.js'
5
+
6
+ async function plugin(fastify, config = {}) {
7
+ const prefix = config.prefix || '/api';
8
+ fastify.decorate('addCron', addCron);
9
+ fastify.get(`${prefix}/cron/:name`, { schema: cronSchema }, cronApi);
10
+ }
11
+
12
+ export default plugin;
package/cron/schema.js ADDED
@@ -0,0 +1,8 @@
1
+ const cronSchema = {
2
+ params: {
3
+ name: { type: 'string', pattern: '^([\\d\\w._-]+)$' },
4
+ },
5
+ };
6
+
7
+ export default null;
8
+ export { cronSchema };
@@ -1,36 +1,36 @@
1
- import {
2
- dataDelete, getTemplate, getAccess, applyHook, getToken, config,
3
- } from '../../utils.js';
4
-
5
- export default async function deleteCrud(req) {
6
- const { user, params = {} } = req || {};
7
- const hookData = await applyHook('preDelete', {
8
- table: params?.table, id: params?.id, user,
9
- });
10
- if (hookData?.message && hookData?.status) {
11
- return { message: hookData?.message, status: hookData?.status };
12
- }
13
-
14
- const tokenData = await getToken({
15
- uid: user.uid, token: params.table, mode: 'w', json: 1,
16
- });
17
-
18
- const { table: del, id } = hookData || tokenData || (config.auth?.disable ? req.params : {});
19
- const { actions = [] } = await getAccess({ table: del, id, user }) || {};
20
-
21
- if (!actions.includes('del')) {
22
- return { message: 'access restricted', status: 403 };
23
- }
24
- const loadTemplate = await getTemplate('table', del);
25
-
26
- const { table } = loadTemplate || hookData || req.params || {};
27
-
28
- if (!table) return { status: 404, message: 'table is required' };
29
- if (!id) return { status: 404, message: 'id is required' };
30
-
31
- const data = await dataDelete({
32
- table, id, uid: user?.uid,
33
- });
34
-
35
- return { rowCount: data.rowCount, msg: !data.rowCount ? data : null };
36
- }
1
+ import {
2
+ dataDelete, getTemplate, getAccess, applyHook, getToken, config,
3
+ } from '../../utils.js';
4
+
5
+ export default async function deleteCrud(req) {
6
+ const { user, params = {} } = req || {};
7
+ const hookData = await applyHook('preDelete', {
8
+ table: params?.table, id: params?.id, user,
9
+ });
10
+ if (hookData?.message && hookData?.status) {
11
+ return { message: hookData?.message, status: hookData?.status };
12
+ }
13
+
14
+ const tokenData = await getToken({
15
+ uid: user.uid, token: params.table, mode: 'w', json: 1,
16
+ });
17
+
18
+ const { table: del, id } = hookData || tokenData || (config.auth?.disable ? req.params : {});
19
+ const { actions = [] } = await getAccess({ table: del, id, user }) || {};
20
+
21
+ if (!actions.includes('del')) {
22
+ return { message: 'access restricted', status: 403 };
23
+ }
24
+ const loadTemplate = await getTemplate('table', del);
25
+
26
+ const { table } = loadTemplate || hookData || req.params || {};
27
+
28
+ if (!table) return { status: 404, message: 'table is required' };
29
+ if (!id) return { status: 404, message: 'id is required' };
30
+
31
+ const data = await dataDelete({
32
+ table, id, uid: user?.uid,
33
+ });
34
+
35
+ return { rowCount: data.rowCount, msg: !data.rowCount ? data : null };
36
+ }
@@ -1,71 +1,71 @@
1
- import {
2
- applyHook, getAccess, getTemplate, checkXSS, dataInsert, getToken, config,
3
- } from '../../utils.js';
4
-
5
- export default async function insert(req) {
6
- const {
7
- user, params = {}, body = {},
8
- } = req || {};
9
- const hookData = await applyHook('preInsert', { table: params?.table, user });
10
- if (hookData?.message && hookData?.status) {
11
- return { message: hookData?.message, status: hookData?.status };
12
- }
13
- const tokenData = await getToken({
14
- uid: user.uid, token: params.table, mode: 'a', json: 1,
15
- });
16
-
17
- const { form, table: add } = hookData || tokenData || (config.auth?.disable ? req.params : {});
18
-
19
- const { actions = [] } = await getAccess({ table: add, user }) || {};
20
-
21
- if (!actions.includes('add')) return { message: 'access restricted', status: 403 };
22
-
23
- if (!add) {
24
- return { message: 'table is required', status: 400 };
25
- }
26
-
27
- const loadTemplate = await getTemplate('table', add);
28
- const { table } = loadTemplate || hookData || req.params || {};
29
- if (!table) {
30
- return { message: 'table not found', status: 404 };
31
- }
32
-
33
- const formData = form || loadTemplate?.form ? (await getTemplate('form', form || loadTemplate?.form) || {}) : {};
34
-
35
- const xssCheck = checkXSS({ body, schema: formData?.schema || formData });
36
-
37
- if (xssCheck.error && formData?.xssCheck !== false) {
38
- req.log.warn({ name: 'injection/xss', msg: xssCheck.error, table }, req);
39
- return { message: 'Дані містять заборонені символи. Приберіть їх та спробуйте ще раз', status: 409 };
40
- }
41
-
42
- const uid = user?.uid;
43
- if ((add || table) !== 'admin.users') {
44
- Object.assign(body, { uid, editor_id: uid });
45
- }
46
- const res = await dataInsert({
47
- table: loadTemplate?.table, data: body, uid,
48
- });
49
-
50
- // admin.custom_column
51
- await applyHook('afterInsert', {
52
- table, body, payload: res, user,
53
- });
54
- // form DataTable
55
- const extraKeys = Object.keys(formData)?.filter((key) => formData?.[key]?.type === 'DataTable' && formData?.[key]?.table && formData?.[key]?.parent_id && body[key].length);
56
- if (extraKeys?.length) {
57
- res.extra = {};
58
- await Promise.all(extraKeys?.map(async (key) => {
59
- const objId = body[formData[key].parent_id] || req.body?.id;
60
- const extraRows = await Promise.all(body[key].map(async (row) => {
61
- const extraRes = await dataInsert({
62
- table: formData[key].table, data: { ...row, [formData[key].parent_id]: objId }, uid,
63
- });
64
- return extraRes?.rows?.[0];
65
- }));
66
- Object.assign(res.extra, { [key]: extraRows.filter((el) => el) });
67
- }));
68
- }
69
-
70
- return { rows: res.rows, extra: res.extra };
71
- }
1
+ import {
2
+ applyHook, getAccess, getTemplate, checkXSS, dataInsert, getToken, config,
3
+ } from '../../utils.js';
4
+
5
+ export default async function insert(req) {
6
+ const {
7
+ user, params = {}, body = {},
8
+ } = req || {};
9
+ const hookData = await applyHook('preInsert', { table: params?.table, user });
10
+ if (hookData?.message && hookData?.status) {
11
+ return { message: hookData?.message, status: hookData?.status };
12
+ }
13
+ const tokenData = await getToken({
14
+ uid: user.uid, token: params.table, mode: 'a', json: 1,
15
+ });
16
+
17
+ const { form, table: add } = hookData || tokenData || (config.auth?.disable ? req.params : {});
18
+
19
+ const { actions = [] } = await getAccess({ table: add, user }) || {};
20
+
21
+ if (!actions.includes('add')) return { message: 'access restricted', status: 403 };
22
+
23
+ if (!add) {
24
+ return { message: 'table is required', status: 400 };
25
+ }
26
+
27
+ const loadTemplate = await getTemplate('table', add);
28
+ const { table } = loadTemplate || hookData || req.params || {};
29
+ if (!table) {
30
+ return { message: 'table not found', status: 404 };
31
+ }
32
+
33
+ const formData = form || loadTemplate?.form ? (await getTemplate('form', form || loadTemplate?.form) || {}) : {};
34
+
35
+ const xssCheck = checkXSS({ body, schema: formData?.schema || formData });
36
+
37
+ if (xssCheck.error && formData?.xssCheck !== false) {
38
+ req.log.warn({ name: 'injection/xss', msg: xssCheck.error, table }, req);
39
+ return { message: 'Дані містять заборонені символи. Приберіть їх та спробуйте ще раз', status: 409 };
40
+ }
41
+
42
+ const uid = user?.uid;
43
+ if ((add || table) !== 'admin.users') {
44
+ Object.assign(body, { uid, editor_id: uid });
45
+ }
46
+ const res = await dataInsert({
47
+ table: loadTemplate?.table, data: body, uid,
48
+ });
49
+
50
+ // admin.custom_column
51
+ await applyHook('afterInsert', {
52
+ table, body, payload: res, user,
53
+ });
54
+ // form DataTable
55
+ const extraKeys = Object.keys(formData)?.filter((key) => formData?.[key]?.type === 'DataTable' && formData?.[key]?.table && formData?.[key]?.parent_id && body[key].length);
56
+ if (extraKeys?.length) {
57
+ res.extra = {};
58
+ await Promise.all(extraKeys?.map(async (key) => {
59
+ const objId = body[formData[key].parent_id] || req.body?.id;
60
+ const extraRows = await Promise.all(body[key].map(async (row) => {
61
+ const extraRes = await dataInsert({
62
+ table: formData[key].table, data: { ...row, [formData[key].parent_id]: objId }, uid,
63
+ });
64
+ return extraRes?.rows?.[0];
65
+ }));
66
+ Object.assign(res.extra, { [key]: extraRows.filter((el) => el) });
67
+ }));
68
+ }
69
+
70
+ return { rows: res.rows, extra: res.extra };
71
+ }