@opengis/admin 0.3.19 → 0.3.20
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/README.md +97 -97
- package/config.js +4 -4
- package/dist/{add-page-BZ4-a4Ds.js → add-page-DsqxZzEq.js} +1 -1
- package/dist/{admin-interface-Cel1oSUl.js → admin-interface-C8SGlC1N.js} +2 -2
- package/dist/{admin-view-DI3sCqf2.js → admin-view-DtdqTUPa.js} +2 -2
- package/dist/admin.js +1 -1
- package/dist/admin.umd.cjs +75 -75
- package/dist/assets/logo.svg +41 -41
- package/dist/{card-view-D8BG77Bz.js → card-view-juhvChuX.js} +1 -1
- package/dist/{edit-page-BEGG0O_f.js → edit-page-DB1hlRzp.js} +1 -1
- package/dist/{import-file-D-rfELS1.js → import-file-BSdaeh6s.js} +17380 -17196
- package/dist/{profile-page-BZczsbQL.js → profile-page-B-RhB5JP.js} +1 -1
- package/dist/style.css +1 -1
- package/module/settings/card/admin.accounts.table/index.yml +7 -7
- package/module/settings/card/admin.accounts.table/rules.hbs +18 -18
- package/module/settings/card/admin.accounts.table/users.hbs +13 -13
- package/module/settings/card/admin.routes.table/groups.hbs +11 -11
- package/module/settings/card/admin.routes.table/users.hbs +16 -16
- package/module/settings/cls/core.actions.json +17 -17
- package/module/settings/cls/core.scope.json +13 -13
- package/module/settings/cls/properties.site_status.json +13 -13
- package/module/settings/cls/properties.widget_status.json +13 -13
- package/module/settings/cls/users.user_type.json +13 -13
- package/module/settings/cls/yes_no.json +11 -11
- package/module/settings/form/admin.accounts.form.json +13 -13
- package/module/settings/form/admin.properties.form.json +15 -15
- package/module/settings/form/admin.roles.form.json +21 -21
- package/module/settings/form/admin.user_properties.form.json +15 -15
- package/module/settings/form/admin.user_roles_card.form.json +13 -13
- package/module/settings/interface/admin.properties.json +4 -4
- package/module/settings/interface/admin.roles.json +4 -4
- package/module/settings/interface/admin.routes.json +4 -4
- package/module/settings/interface/admin.users.json +4 -4
- package/module/settings/select/core.routes.sql +1 -1
- package/module/settings/select/core.user_mentioned.sql +1 -1
- package/module/settings/select/core.user_uid.sql +1 -1
- package/module/settings/table/admin.properties.table.json +39 -39
- package/module/settings/table/admin.user_properties.table.json +34 -34
- package/package.json +5 -4
- package/server/helpers/core/badge.js +16 -16
- package/server/helpers/core/buttonHelper.js +21 -21
- package/server/helpers/core/coalesce.js +7 -7
- package/server/helpers/core/select.js +48 -48
- package/server/helpers/core/token.js +18 -18
- package/server/helpers/list/buttonHelper.js +21 -21
- package/server/helpers/list/utils/button.js +5 -5
- package/server/helpers/temp/contentList.js +58 -58
- package/server/helpers/temp/ifCond.js +101 -101
- package/server/helpers/utils/button.js +5 -5
- package/server/helpers/utils/mdToHTML.js +17 -17
- package/server/plugins/access/index.mjs +6 -6
- package/server/plugins/adminHook.js +81 -81
- package/server/plugins/cron.js +10 -10
- package/server/plugins/docs.js +28 -28
- package/server/plugins/hook.js +19 -8
- package/server/routes/access/controllers/access.group.js +29 -29
- package/server/routes/access/controllers/access.group.post.js +54 -54
- package/server/routes/access/index.mjs +11 -11
- package/server/routes/access/schema.mjs +67 -67
- package/server/routes/calendar/controllers/calendar.data.js +125 -125
- package/server/routes/calendar/index.mjs +7 -7
- package/server/routes/calendar/schema.js +21 -21
- package/server/routes/data/controllers/cardTabData.js +49 -49
- package/server/routes/data/controllers/funcs/getFilterSQL/index.js +92 -92
- package/server/routes/data/controllers/funcs/getFilterSQL/util/formatValue.js +170 -170
- package/server/routes/data/controllers/funcs/getFilterSQL/util/getCustomQuery.js +13 -13
- package/server/routes/data/controllers/funcs/getFilterSQL/util/getFilterQuery.js +64 -64
- package/server/routes/data/controllers/funcs/getFilterSQL/util/getOptimizedQuery.js +12 -12
- package/server/routes/data/controllers/funcs/getFilterSQL/util/getTableSql.js +34 -34
- package/server/routes/data/controllers/tableData.js +31 -31
- package/server/routes/data/controllers/tableDataId.js +27 -27
- package/server/routes/data/controllers/tokenInfo.js +9 -9
- package/server/routes/data/controllers/utils/assignTokens.js +30 -30
- package/server/routes/data/controllers/utils/conditions.js +20 -20
- package/server/routes/data/controllers/utils/getColumns.js +8 -8
- package/server/routes/data/index.mjs +20 -20
- package/server/routes/data/schema.js +54 -54
- package/server/routes/notifications/controllers/readNotifications.js +27 -27
- package/server/routes/notifications/controllers/testEmail.js +35 -35
- package/server/routes/notifications/controllers/userNotifications.js +53 -53
- package/server/routes/notifications/funcs/addNotification.js +21 -21
- package/server/routes/notifications/funcs/sendNotification.js +92 -92
- package/server/routes/notifications/hook/onWidgetSet.js +56 -56
- package/server/routes/notifications/index.mjs +26 -26
- package/server/routes/notifications/schema.js +16 -16
- package/server/routes/print/controllers/cardPrint.js +135 -135
- package/server/routes/properties/schema.js +10 -10
- package/server/routes/report/controllers/data.js +76 -76
- package/server/routes/report/controllers/list.js +18 -18
- package/server/routes/report/index.mjs +7 -7
- package/server/routes/report/utils/formatValue.js +179 -179
- package/server/routes/root.mjs +3 -3
- package/server/routes/templates/controllers/getTemplate.js +44 -44
- package/server/routes/templates/schema.js +8 -8
- package/server/routes/user/controllers/user.cls.id.js +14 -14
- package/server/routes/user/controllers/user.cls.js +72 -72
- package/server/routes/user/controllers/user.info.js +17 -17
- package/server/routes/user/schema.js +14 -14
- package/server/routes/util/controllers/code.generator.js +89 -89
- package/server/routes/widget/controllers/widget.del.js +47 -47
- package/server/routes/widget/controllers/widget.set.js +84 -84
- package/server/routes/widget/hook/onWidgetSet.js +12 -12
- package/server/routes/widget/index.mjs +16 -16
- package/server/routes/widget/schema.js +12 -12
- package/server/templates/cls/itree.recrzone_category.json +73 -73
- package/server/templates/cls/test.json +9 -9
- package/server/templates/form/admin.user_cls.data.form.json +49 -49
- package/server/templates/form/admin.user_group_rel.form.json +21 -21
- package/server/templates/form/form-user-pass.json +10 -10
- package/server/templates/form/form-user_group.json +39 -39
- package/server/templates/form/form-users.json +156 -156
- package/server/templates/form/user_group_access.form.json +22 -22
- package/server/templates/select/account_id.json +2 -2
- package/server/templates/table/gis.dataset.table.json +43 -43
- package/server/templates/table/management.user_group.table.json +112 -112
- package/server/templates/table/management.users.table.json +126 -126
@@ -1,101 +1,101 @@
|
|
1
|
-
/**
|
2
|
-
* Перетинає два масиви
|
3
|
-
*
|
4
|
-
* @example
|
5
|
-
* // returns [1, 4, 5, 6]
|
6
|
-
* intersect([1,2,3,4,5,6],[1,4,5,6,7,8,9,11])
|
7
|
-
* @param {Array} a
|
8
|
-
* @param {Array} b
|
9
|
-
* @returns {Array} Returns new intersect array
|
10
|
-
*/
|
11
|
-
function intersect(a, b) {
|
12
|
-
let aN = a; let bN = b;
|
13
|
-
if (b.length > a.length) {
|
14
|
-
[aN, bN] = [bN, aN];
|
15
|
-
}
|
16
|
-
return aN.filter((e) => bN.includes(e));
|
17
|
-
}
|
18
|
-
|
19
|
-
/**
|
20
|
-
* Створення шаблона або його частини внаслідок перевірки значення із веб-запиту та заздалегідь прописаного значення.
|
21
|
-
* Дозволяє змінювати наповнення сторінки через ряд перевірок. Є можливість внесення додаткової умови - що робити, коли умова не виконується.
|
22
|
-
*
|
23
|
-
* @summary Перевірка двох значень та виконання коду при виконанні умови, а також у всіх інших випадках.
|
24
|
-
* @priority 5
|
25
|
-
* @alias ifCond
|
26
|
-
* @type helper
|
27
|
-
* @tag condition
|
28
|
-
* @example
|
29
|
-
* {{#ifCond @root.req.domain 'in' 'help.softpro.ua,123'}} {{select user.uid data="get_full_uid"}} {{^}} Умова не виконана {{/ifCond}}
|
30
|
-
* @example
|
31
|
-
* {{#ifCond "1234567890" 'in' @root.user.group_list}} 1=1 {{^}} uid='{{uid}}' {{/ifCond}}
|
32
|
-
* @example
|
33
|
-
* {{#ifCond 'debug' 'in' @root.setting.core.setting}}Умова виконана{{^}}Не виконана умова{{/ifCond}}
|
34
|
-
* @param {Array} args Параметри для значень і умов
|
35
|
-
* @param {Array} args[0]] Перше значення
|
36
|
-
* @param {Array} args[1]] Оператор
|
37
|
-
* @param {Array} args[2]] Друге значення
|
38
|
-
* @returns {String} Returns HTML
|
39
|
-
*/
|
40
|
-
export default function ifCond(v1, operator, v2, options) {
|
41
|
-
const __obj = this;
|
42
|
-
|
43
|
-
switch (operator) {
|
44
|
-
case '==':
|
45
|
-
return (v1 == v2) ? options.fn(__obj) : options.inverse(__obj);
|
46
|
-
case '!=':
|
47
|
-
return (v1 != v2) ? options.fn(__obj) : options.inverse(__obj);
|
48
|
-
case '===':
|
49
|
-
return (v1 === v2) ? options.fn(__obj) : options.inverse(__obj);
|
50
|
-
case '!==':
|
51
|
-
return (v1 !== v2) ? options.fn(__obj) : options.inverse(__obj);
|
52
|
-
case '&&':
|
53
|
-
return (v1 && v2) ? options.fn(__obj) : options.inverse(__obj);
|
54
|
-
case '||':
|
55
|
-
return (v1 || v2) ? options.fn(__obj) : options.inverse(__obj);
|
56
|
-
case '<':
|
57
|
-
return (v1 < v2) ? options.fn(__obj) : options.inverse(__obj);
|
58
|
-
case '<=':
|
59
|
-
return (v1 <= v2) ? options.fn(__obj) : options.inverse(__obj);
|
60
|
-
case '>':
|
61
|
-
return (v1 > v2) ? options.fn(__obj) : options.inverse(__obj);
|
62
|
-
case '>=':
|
63
|
-
return (v1 >= v2) ? options.fn(__obj) : options.inverse(__obj);
|
64
|
-
case '&':
|
65
|
-
return intersect(v1, v2).length !== 0
|
66
|
-
? options.fn(__obj)
|
67
|
-
: options.inverse(__obj);
|
68
|
-
case '!~':
|
69
|
-
return (v1 || '').indexOf(v2) === -1
|
70
|
-
? options.fn(__obj)
|
71
|
-
: options.inverse(__obj);
|
72
|
-
case '~':
|
73
|
-
return (v1 || '').indexOf(v2) !== -1
|
74
|
-
? options.fn(__obj)
|
75
|
-
: options.inverse(__obj);
|
76
|
-
case 'period':
|
77
|
-
return (new Date(v1) < new Date() && new Date(v2) > new Date())
|
78
|
-
? options.fn(__obj)
|
79
|
-
: options.inverse(__obj);
|
80
|
-
case 'in': {
|
81
|
-
if (typeof v2 === 'string') v2 = v2.split(',').map(item => item.trim());
|
82
|
-
|
83
|
-
if (Array.isArray(v1)) {
|
84
|
-
return v1.some((value) => v2.includes(value.toString()))
|
85
|
-
? options.fn(__obj)
|
86
|
-
: options.inverse(__obj);
|
87
|
-
}
|
88
|
-
return v2.includes(v1?.toString())
|
89
|
-
? options.fn(__obj)
|
90
|
-
: options.inverse(__obj);
|
91
|
-
}
|
92
|
-
case 'not in': {
|
93
|
-
if (typeof v2 === 'string') v2 = v2.split(',').map(item => item.trim());
|
94
|
-
return !v2.includes(v1?.toString())
|
95
|
-
? options.fn(__obj)
|
96
|
-
: options.inverse(__obj);
|
97
|
-
}
|
98
|
-
default:
|
99
|
-
return options.inverse(__obj);
|
100
|
-
}
|
101
|
-
}
|
1
|
+
/**
|
2
|
+
* Перетинає два масиви
|
3
|
+
*
|
4
|
+
* @example
|
5
|
+
* // returns [1, 4, 5, 6]
|
6
|
+
* intersect([1,2,3,4,5,6],[1,4,5,6,7,8,9,11])
|
7
|
+
* @param {Array} a
|
8
|
+
* @param {Array} b
|
9
|
+
* @returns {Array} Returns new intersect array
|
10
|
+
*/
|
11
|
+
function intersect(a, b) {
|
12
|
+
let aN = a; let bN = b;
|
13
|
+
if (b.length > a.length) {
|
14
|
+
[aN, bN] = [bN, aN];
|
15
|
+
}
|
16
|
+
return aN.filter((e) => bN.includes(e));
|
17
|
+
}
|
18
|
+
|
19
|
+
/**
|
20
|
+
* Створення шаблона або його частини внаслідок перевірки значення із веб-запиту та заздалегідь прописаного значення.
|
21
|
+
* Дозволяє змінювати наповнення сторінки через ряд перевірок. Є можливість внесення додаткової умови - що робити, коли умова не виконується.
|
22
|
+
*
|
23
|
+
* @summary Перевірка двох значень та виконання коду при виконанні умови, а також у всіх інших випадках.
|
24
|
+
* @priority 5
|
25
|
+
* @alias ifCond
|
26
|
+
* @type helper
|
27
|
+
* @tag condition
|
28
|
+
* @example
|
29
|
+
* {{#ifCond @root.req.domain 'in' 'help.softpro.ua,123'}} {{select user.uid data="get_full_uid"}} {{^}} Умова не виконана {{/ifCond}}
|
30
|
+
* @example
|
31
|
+
* {{#ifCond "1234567890" 'in' @root.user.group_list}} 1=1 {{^}} uid='{{uid}}' {{/ifCond}}
|
32
|
+
* @example
|
33
|
+
* {{#ifCond 'debug' 'in' @root.setting.core.setting}}Умова виконана{{^}}Не виконана умова{{/ifCond}}
|
34
|
+
* @param {Array} args Параметри для значень і умов
|
35
|
+
* @param {Array} args[0]] Перше значення
|
36
|
+
* @param {Array} args[1]] Оператор
|
37
|
+
* @param {Array} args[2]] Друге значення
|
38
|
+
* @returns {String} Returns HTML
|
39
|
+
*/
|
40
|
+
export default function ifCond(v1, operator, v2, options) {
|
41
|
+
const __obj = this;
|
42
|
+
|
43
|
+
switch (operator) {
|
44
|
+
case '==':
|
45
|
+
return (v1 == v2) ? options.fn(__obj) : options.inverse(__obj);
|
46
|
+
case '!=':
|
47
|
+
return (v1 != v2) ? options.fn(__obj) : options.inverse(__obj);
|
48
|
+
case '===':
|
49
|
+
return (v1 === v2) ? options.fn(__obj) : options.inverse(__obj);
|
50
|
+
case '!==':
|
51
|
+
return (v1 !== v2) ? options.fn(__obj) : options.inverse(__obj);
|
52
|
+
case '&&':
|
53
|
+
return (v1 && v2) ? options.fn(__obj) : options.inverse(__obj);
|
54
|
+
case '||':
|
55
|
+
return (v1 || v2) ? options.fn(__obj) : options.inverse(__obj);
|
56
|
+
case '<':
|
57
|
+
return (v1 < v2) ? options.fn(__obj) : options.inverse(__obj);
|
58
|
+
case '<=':
|
59
|
+
return (v1 <= v2) ? options.fn(__obj) : options.inverse(__obj);
|
60
|
+
case '>':
|
61
|
+
return (v1 > v2) ? options.fn(__obj) : options.inverse(__obj);
|
62
|
+
case '>=':
|
63
|
+
return (v1 >= v2) ? options.fn(__obj) : options.inverse(__obj);
|
64
|
+
case '&':
|
65
|
+
return intersect(v1, v2).length !== 0
|
66
|
+
? options.fn(__obj)
|
67
|
+
: options.inverse(__obj);
|
68
|
+
case '!~':
|
69
|
+
return (v1 || '').indexOf(v2) === -1
|
70
|
+
? options.fn(__obj)
|
71
|
+
: options.inverse(__obj);
|
72
|
+
case '~':
|
73
|
+
return (v1 || '').indexOf(v2) !== -1
|
74
|
+
? options.fn(__obj)
|
75
|
+
: options.inverse(__obj);
|
76
|
+
case 'period':
|
77
|
+
return (new Date(v1) < new Date() && new Date(v2) > new Date())
|
78
|
+
? options.fn(__obj)
|
79
|
+
: options.inverse(__obj);
|
80
|
+
case 'in': {
|
81
|
+
if (typeof v2 === 'string') v2 = v2.split(',').map(item => item.trim());
|
82
|
+
|
83
|
+
if (Array.isArray(v1)) {
|
84
|
+
return v1.some((value) => v2.includes(value.toString()))
|
85
|
+
? options.fn(__obj)
|
86
|
+
: options.inverse(__obj);
|
87
|
+
}
|
88
|
+
return v2.includes(v1?.toString())
|
89
|
+
? options.fn(__obj)
|
90
|
+
: options.inverse(__obj);
|
91
|
+
}
|
92
|
+
case 'not in': {
|
93
|
+
if (typeof v2 === 'string') v2 = v2.split(',').map(item => item.trim());
|
94
|
+
return !v2.includes(v1?.toString())
|
95
|
+
? options.fn(__obj)
|
96
|
+
: options.inverse(__obj);
|
97
|
+
}
|
98
|
+
default:
|
99
|
+
return options.inverse(__obj);
|
100
|
+
}
|
101
|
+
}
|
@@ -1,6 +1,6 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
export default function button(token, title) {
|
4
|
-
return `<button onclick="window.v3plugin.$form({ token: '${token}' })"
|
5
|
-
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>`;
|
1
|
+
|
2
|
+
|
3
|
+
export default function button(token, title) {
|
4
|
+
return `<button onclick="window.v3plugin.$form({ token: '${token}' })"
|
5
|
+
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>`;
|
6
6
|
}
|
@@ -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, options) {
|
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, options) {
|
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,6 +1,6 @@
|
|
1
|
-
import getAdminAccess from './funcs/getAdminAccess.js';
|
2
|
-
|
3
|
-
async function plugin(fastify) {
|
4
|
-
// fastify.decorate('getAdminAccess', getAdminAccess);
|
5
|
-
}
|
6
|
-
export default plugin;
|
1
|
+
import getAdminAccess from './funcs/getAdminAccess.js';
|
2
|
+
|
3
|
+
async function plugin(fastify) {
|
4
|
+
// fastify.decorate('getAdminAccess', getAdminAccess);
|
5
|
+
}
|
6
|
+
export default plugin;
|
@@ -1,81 +1,81 @@
|
|
1
|
-
import fp from 'fastify-plugin';
|
2
|
-
import fs from 'node:fs';
|
3
|
-
|
4
|
-
import config from '../../config.js';
|
5
|
-
|
6
|
-
// to export the decorators to the outer scope
|
7
|
-
|
8
|
-
async function plugin(fastify) {
|
9
|
-
fastify.decorate('config', config);
|
10
|
-
|
11
|
-
// preSerialization
|
12
|
-
fastify.addHook('preSerialization', async (req, reply, payload) => {
|
13
|
-
if (req.url.includes('/suggest/') && !req.query.json) {
|
14
|
-
return payload?.data;
|
15
|
-
}
|
16
|
-
if (payload?.redirect) {
|
17
|
-
return reply.redirect(payload.redirect);
|
18
|
-
}
|
19
|
-
if (reply.sent) {
|
20
|
-
return null;
|
21
|
-
}
|
22
|
-
|
23
|
-
if ([200, 400, 403, 409, 404, 500].includes(payload.status)) {
|
24
|
-
reply.status(payload.status);
|
25
|
-
}
|
26
|
-
/* if (payload.headers) {
|
27
|
-
reply.headers(payload.headers);
|
28
|
-
} */
|
29
|
-
if (payload?.buffer) {
|
30
|
-
return payload.buffer;
|
31
|
-
}
|
32
|
-
if (payload?.file) {
|
33
|
-
// const buffer = await readFile(payload.file);
|
34
|
-
// return reply.send(buffer);
|
35
|
-
const stream = fs.createReadStream(payload.file);
|
36
|
-
return stream;
|
37
|
-
// return reply.send(stream);
|
38
|
-
}
|
39
|
-
|
40
|
-
if (payload?.message) {
|
41
|
-
return payload.message;
|
42
|
-
}
|
43
|
-
return payload;
|
44
|
-
});
|
45
|
-
|
46
|
-
// preValidation
|
47
|
-
fastify.addHook('preValidation', async (req) => {
|
48
|
-
const parseRawBody = ['POST', 'PUT'].includes(req.method) && req.body && typeof req.body === 'string'
|
49
|
-
&& req.body.trim(/\r\n/g).startsWith('{')
|
50
|
-
&& req.body.trim(/\r\n/g).endsWith('}');
|
51
|
-
if (parseRawBody) {
|
52
|
-
try {
|
53
|
-
req.body = JSON.parse(req.body || '{}');
|
54
|
-
}
|
55
|
-
catch (err) {
|
56
|
-
// throw new Error('invalid body');
|
57
|
-
// return { error: 'invalid body', status: 400 };
|
58
|
-
}
|
59
|
-
}
|
60
|
-
});
|
61
|
-
|
62
|
-
// allow upload file
|
63
|
-
const kIsMultipart = Symbol.for('[FastifyMultipart.isMultipart]');
|
64
|
-
fastify.addContentTypeParser('multipart', (request, _, done) => {
|
65
|
-
request[kIsMultipart] = true;
|
66
|
-
done(null);
|
67
|
-
});
|
68
|
-
|
69
|
-
// parse Body
|
70
|
-
function contentParser(req, body, done) {
|
71
|
-
const parseBody = decodeURIComponent(body.toString()).split('&').reduce((acc, el) => {
|
72
|
-
const [key, val] = el.split('=');
|
73
|
-
return { ...acc, [key]: val };
|
74
|
-
}, {});
|
75
|
-
done(null, parseBody);
|
76
|
-
}
|
77
|
-
|
78
|
-
fastify.addContentTypeParser('application/x-www-form-urlencoded', { parseAs: 'buffer' }, contentParser);
|
79
|
-
}
|
80
|
-
|
81
|
-
export default fp(plugin);
|
1
|
+
import fp from 'fastify-plugin';
|
2
|
+
import fs from 'node:fs';
|
3
|
+
|
4
|
+
import config from '../../config.js';
|
5
|
+
|
6
|
+
// to export the decorators to the outer scope
|
7
|
+
|
8
|
+
async function plugin(fastify) {
|
9
|
+
fastify.decorate('config', config);
|
10
|
+
|
11
|
+
// preSerialization
|
12
|
+
fastify.addHook('preSerialization', async (req, reply, payload) => {
|
13
|
+
if (req.url.includes('/suggest/') && !req.query.json) {
|
14
|
+
return payload?.data;
|
15
|
+
}
|
16
|
+
if (payload?.redirect) {
|
17
|
+
return reply.redirect(payload.redirect);
|
18
|
+
}
|
19
|
+
if (reply.sent) {
|
20
|
+
return null;
|
21
|
+
}
|
22
|
+
|
23
|
+
if ([200, 400, 403, 409, 404, 500].includes(payload.status)) {
|
24
|
+
reply.status(payload.status);
|
25
|
+
}
|
26
|
+
/* if (payload.headers) {
|
27
|
+
reply.headers(payload.headers);
|
28
|
+
} */
|
29
|
+
if (payload?.buffer) {
|
30
|
+
return payload.buffer;
|
31
|
+
}
|
32
|
+
if (payload?.file) {
|
33
|
+
// const buffer = await readFile(payload.file);
|
34
|
+
// return reply.send(buffer);
|
35
|
+
const stream = fs.createReadStream(payload.file);
|
36
|
+
return stream;
|
37
|
+
// return reply.send(stream);
|
38
|
+
}
|
39
|
+
|
40
|
+
if (payload?.message) {
|
41
|
+
return payload.message;
|
42
|
+
}
|
43
|
+
return payload;
|
44
|
+
});
|
45
|
+
|
46
|
+
// preValidation
|
47
|
+
fastify.addHook('preValidation', async (req) => {
|
48
|
+
const parseRawBody = ['POST', 'PUT'].includes(req.method) && req.body && typeof req.body === 'string'
|
49
|
+
&& req.body.trim(/\r\n/g).startsWith('{')
|
50
|
+
&& req.body.trim(/\r\n/g).endsWith('}');
|
51
|
+
if (parseRawBody) {
|
52
|
+
try {
|
53
|
+
req.body = JSON.parse(req.body || '{}');
|
54
|
+
}
|
55
|
+
catch (err) {
|
56
|
+
// throw new Error('invalid body');
|
57
|
+
// return { error: 'invalid body', status: 400 };
|
58
|
+
}
|
59
|
+
}
|
60
|
+
});
|
61
|
+
|
62
|
+
// allow upload file
|
63
|
+
const kIsMultipart = Symbol.for('[FastifyMultipart.isMultipart]');
|
64
|
+
fastify.addContentTypeParser('multipart', (request, _, done) => {
|
65
|
+
request[kIsMultipart] = true;
|
66
|
+
done(null);
|
67
|
+
});
|
68
|
+
|
69
|
+
// parse Body
|
70
|
+
function contentParser(req, body, done) {
|
71
|
+
const parseBody = decodeURIComponent(body.toString()).split('&').reduce((acc, el) => {
|
72
|
+
const [key, val] = el.split('=');
|
73
|
+
return { ...acc, [key]: val };
|
74
|
+
}, {});
|
75
|
+
done(null, parseBody);
|
76
|
+
}
|
77
|
+
|
78
|
+
fastify.addContentTypeParser('application/x-www-form-urlencoded', { parseAs: 'buffer' }, contentParser);
|
79
|
+
}
|
80
|
+
|
81
|
+
export default fp(plugin);
|
package/server/plugins/cron.js
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
//import { addCron } from '@opengis/fastify-table/utils.js';
|
2
|
-
|
3
|
-
async function deleteOldNotifications({ pg }) {
|
4
|
-
const { rowCount } = pg?.pk?.['crm.notifications'] ? await pg.query('delete from crm.notifications where CURRENT_DATE - \'14 days\'::interval > cdate') : {};
|
5
|
-
return { rowCount };
|
6
|
-
}
|
7
|
-
|
8
|
-
export default async function cron(fastify) {
|
9
|
-
// addCron(deleteOldNotifications, 60 * 60 * 24, fastify);
|
10
|
-
// addCron(deleteOldNotifications, 60 * 1, fastify); // debug
|
1
|
+
//import { addCron } from '@opengis/fastify-table/utils.js';
|
2
|
+
|
3
|
+
async function deleteOldNotifications({ pg }) {
|
4
|
+
const { rowCount } = pg?.pk?.['crm.notifications'] ? await pg.query('delete from crm.notifications where CURRENT_DATE - \'14 days\'::interval > cdate') : {};
|
5
|
+
return { rowCount };
|
6
|
+
}
|
7
|
+
|
8
|
+
export default async function cron(fastify) {
|
9
|
+
// addCron(deleteOldNotifications, 60 * 60 * 24, fastify);
|
10
|
+
// addCron(deleteOldNotifications, 60 * 1, fastify); // debug
|
11
11
|
}
|
package/server/plugins/docs.js
CHANGED
@@ -1,28 +1,28 @@
|
|
1
|
-
'use strict'
|
2
|
-
|
3
|
-
import path, { dirname } from 'path';
|
4
|
-
import { fileURLToPath } from 'url';
|
5
|
-
import fs from 'fs';
|
6
|
-
|
7
|
-
const dir = dirname(fileURLToPath(import.meta.url));
|
8
|
-
const root = `${dir}/../../`;
|
9
|
-
|
10
|
-
|
11
|
-
async function plugin(fastify, opts) {
|
12
|
-
fastify.get('/docs*', async (req, reply) => {
|
13
|
-
if (!fs.existsSync(path.join(root, 'docs/.vitepress/dist/'))) {
|
14
|
-
return reply.status(404).send('docs not exists');
|
15
|
-
}
|
16
|
-
const { params } = req;
|
17
|
-
const url = params['*']
|
18
|
-
const filePath = url && url[url.length - 1] !== '/' ? path.join(root, 'docs/.vitepress/dist/', url) : path.join(root, 'docs/.vitepress/dist/', url, 'index.html')
|
19
|
-
const ext = path.extname(filePath);
|
20
|
-
const mime = {
|
21
|
-
'.js': 'text/javascript', '.css': 'text/css', '.woff2': 'application/font-woff', '.png': 'image/png', '.svg': 'image/svg+xml', '.jpg': 'image/jpg'
|
22
|
-
}[ext];
|
23
|
-
const stream = fs.createReadStream(filePath);
|
24
|
-
return mime ? reply.type(mime).send(stream) : stream;
|
25
|
-
|
26
|
-
})
|
27
|
-
}
|
28
|
-
export default plugin;
|
1
|
+
'use strict'
|
2
|
+
|
3
|
+
import path, { dirname } from 'path';
|
4
|
+
import { fileURLToPath } from 'url';
|
5
|
+
import fs from 'fs';
|
6
|
+
|
7
|
+
const dir = dirname(fileURLToPath(import.meta.url));
|
8
|
+
const root = `${dir}/../../`;
|
9
|
+
|
10
|
+
|
11
|
+
async function plugin(fastify, opts) {
|
12
|
+
fastify.get('/docs*', async (req, reply) => {
|
13
|
+
if (!fs.existsSync(path.join(root, 'docs/.vitepress/dist/'))) {
|
14
|
+
return reply.status(404).send('docs not exists');
|
15
|
+
}
|
16
|
+
const { params } = req;
|
17
|
+
const url = params['*']
|
18
|
+
const filePath = url && url[url.length - 1] !== '/' ? path.join(root, 'docs/.vitepress/dist/', url) : path.join(root, 'docs/.vitepress/dist/', url, 'index.html')
|
19
|
+
const ext = path.extname(filePath);
|
20
|
+
const mime = {
|
21
|
+
'.js': 'text/javascript', '.css': 'text/css', '.woff2': 'application/font-woff', '.png': 'image/png', '.svg': 'image/svg+xml', '.jpg': 'image/jpg'
|
22
|
+
}[ext];
|
23
|
+
const stream = fs.createReadStream(filePath);
|
24
|
+
return mime ? reply.type(mime).send(stream) : stream;
|
25
|
+
|
26
|
+
})
|
27
|
+
}
|
28
|
+
export default plugin;
|
package/server/plugins/hook.js
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
import path from 'node:path';
|
2
|
+
import { createHash } from 'node:crypto';
|
2
3
|
import { readFileSync } from 'node:fs';
|
3
4
|
|
4
5
|
import {
|
5
|
-
getTemplatePath, addHook, getToken, getTemplate, config, pgClients,
|
6
|
-
initPG,
|
6
|
+
getTemplatePath, addHook, getToken, getTemplate, config, pgClients, initPG, getRedis, logger,
|
7
7
|
} from '@opengis/fastify-table/utils.js';
|
8
8
|
|
9
9
|
import getMenu from '../routes/menu/controllers/getMenu.js';
|
@@ -11,6 +11,8 @@ import printTemplates from '../routes/print/controllers/printTemplates.js';
|
|
11
11
|
|
12
12
|
const { client } = pgClients;
|
13
13
|
|
14
|
+
const rclient = getRedis();
|
15
|
+
|
14
16
|
export default async function plugin(fastify) {
|
15
17
|
const user1 = config?.auth?.disable || process.env.NODE_ENV !== 'admin' ? { uid: '1' } : null;
|
16
18
|
await initPG(client);
|
@@ -116,26 +118,35 @@ export default async function plugin(fastify) {
|
|
116
118
|
//console.log('cls insert skip dupes', dupes.map((el) => el.name));
|
117
119
|
|
118
120
|
try {
|
119
|
-
await
|
121
|
+
const hashes = await rclient.hgetall('cls-insert-hashes').then(obj => Object.keys(obj));
|
122
|
+
const qHashes = await Promise.all(cls.filter((el, idx, arr) => arr.map((item) => item.name).indexOf(el.name) === idx).map(async (el) => {
|
120
123
|
const { name, module, type } = el;
|
121
124
|
const loadTemplate = await getTemplate(type, name);
|
122
|
-
|
123
|
-
if (type === 'select') {
|
125
|
+
const hash = createHash('md5').update(type === 'cls' ? JSON.stringify(loadTemplate) : (loadTemplate?.sql || loadTemplate)).digest('hex');
|
126
|
+
if (type === 'select' && !hashes.includes(hash)) {
|
124
127
|
clsQuery.push(`insert into admin.cls(name,type,data,module) values('${name}','sql','${(loadTemplate?.sql || loadTemplate)?.replace(/'/g, "''")}', '${module?.replace(/'/g, "''")}')`);
|
125
|
-
|
128
|
+
return hash;
|
129
|
+
} else if (type === 'cls' && loadTemplate?.length && !hashes.includes(hash)) {
|
126
130
|
clsQuery.push(`insert into admin.cls(name,type, module) values('${name}','json', '${module?.replace(/'/g, "''")}');
|
127
131
|
insert into admin.cls(code,name,parent,icon,data)
|
128
132
|
select value->>'id',value->>'text','${name}',value->>'icon',value->>'data'
|
129
133
|
from json_array_elements('${JSON.stringify(loadTemplate).replace(/'/g, "''")}'::json)`);
|
134
|
+
return hash;
|
135
|
+
} else if (hashes.includes(hash)) {
|
136
|
+
console.log(name, type, 'skip equal hash');
|
130
137
|
} else {
|
131
138
|
console.log(name, type, 'empty');
|
132
139
|
}
|
133
140
|
}));
|
134
141
|
|
135
|
-
await client.query('
|
142
|
+
const { rowCount = 0 } = await client.query('delete from admin.cls where name = any($1::text[]) or parent = any($1::text[])', [cls.map(el => el.name)]);
|
143
|
+
console.log('admin/hook old cls deleted', rowCount);
|
136
144
|
if (clsQuery.filter((el) => el).length) {
|
137
|
-
await client.query(clsQuery.filter((el) => el).join(';'));
|
138
145
|
console.log('admin/hook cls sql start', clsQuery?.length);
|
146
|
+
await client.query(clsQuery.filter((el) => el).join(';'));
|
147
|
+
await Promise.all(qHashes.filter(el => el).map(async (el) => rclient.hset('cls-insert-hashes', el, 1)));
|
148
|
+
logger.file('migration/hash', { list: qHashes.filter(el => el) });
|
149
|
+
console.log('admin/hook cls sql finish', clsQuery?.length);
|
139
150
|
}
|
140
151
|
} catch (err) {
|
141
152
|
console.error('admin/hook cls sql error', err.toString());
|
@@ -1,30 +1,30 @@
|
|
1
|
-
import { pgClients } from '@opengis/fastify-table/utils.js';
|
2
|
-
|
3
|
-
import { getAdminAccess } from '../../../../utils.js';
|
4
|
-
|
5
|
-
export default async function accessGroup({
|
6
|
-
pg = pgClients.client, params = {}, session = {},
|
7
|
-
}) {
|
8
|
-
const { user = {} } = session?.passport || {};
|
9
|
-
|
10
|
-
if (!params?.id) {
|
11
|
-
return { message: 'not enough params: id', status: 400 };
|
12
|
-
}
|
13
|
-
|
14
|
-
// restrict access - admin only
|
15
|
-
const check = await getAdminAccess({
|
16
|
-
id: params.id, user,
|
17
|
-
});
|
18
|
-
if (check) return check;
|
19
|
-
|
20
|
-
const { rows: routes = [] } = await pg.query(`select a.route_id as path, b.actions from admin.routes a
|
21
|
-
left join admin.role_access b on a.route_id=b.route_id
|
22
|
-
where b.role_id=$1`, [params.id]);
|
23
|
-
|
24
|
-
const { rows: users = [] } = await pg.query(`select user_uid as id, user_name as name, access_granted,
|
25
|
-
b.cdate as user_created, b.last_activity_date as last_activity from admin.user_roles a
|
26
|
-
left join admin.users b on a.user_uid=b.uid
|
27
|
-
where a.role_id=$1`, [params.id]);
|
28
|
-
|
29
|
-
return { routes, users };
|
1
|
+
import { pgClients } from '@opengis/fastify-table/utils.js';
|
2
|
+
|
3
|
+
import { getAdminAccess } from '../../../../utils.js';
|
4
|
+
|
5
|
+
export default async function accessGroup({
|
6
|
+
pg = pgClients.client, params = {}, session = {},
|
7
|
+
}) {
|
8
|
+
const { user = {} } = session?.passport || {};
|
9
|
+
|
10
|
+
if (!params?.id) {
|
11
|
+
return { message: 'not enough params: id', status: 400 };
|
12
|
+
}
|
13
|
+
|
14
|
+
// restrict access - admin only
|
15
|
+
const check = await getAdminAccess({
|
16
|
+
id: params.id, user,
|
17
|
+
});
|
18
|
+
if (check) return check;
|
19
|
+
|
20
|
+
const { rows: routes = [] } = await pg.query(`select a.route_id as path, b.actions from admin.routes a
|
21
|
+
left join admin.role_access b on a.route_id=b.route_id
|
22
|
+
where b.role_id=$1`, [params.id]);
|
23
|
+
|
24
|
+
const { rows: users = [] } = await pg.query(`select user_uid as id, user_name as name, access_granted,
|
25
|
+
b.cdate as user_created, b.last_activity_date as last_activity from admin.user_roles a
|
26
|
+
left join admin.users b on a.user_uid=b.uid
|
27
|
+
where a.role_id=$1`, [params.id]);
|
28
|
+
|
29
|
+
return { routes, users };
|
30
30
|
}
|