@opengis/admin 0.2.7 → 0.2.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (164) hide show
  1. package/README.md +29 -29
  2. package/config.js +4 -4
  3. package/dist/{IconChevronDown-B3Ry6l2F.js → IconChevronDown-BCpDxWU9.js} +1 -1
  4. package/dist/{add-page-Dv6JSPJD.js → add-page-CKy5L_78.js} +1 -1
  5. package/dist/{admin-interface-BWZcS6r_.js → admin-interface-BX613rWQ.js} +259 -260
  6. package/dist/{admin-view-xT8rj54J.js → admin-view-DJBkad_B.js} +3 -3
  7. package/dist/admin.js +1 -1
  8. package/dist/admin.umd.cjs +54 -54
  9. package/dist/assets/logo.svg +41 -41
  10. package/dist/{card-view-DbHBF1Gz.js → card-view-CdCsaogK.js} +1 -1
  11. package/dist/{edit-page-TnYoAVr7.js → edit-page-C76NxZRq.js} +1 -1
  12. package/dist/{import-file-1QgPYOHQ.js → import-file-CknmeGNO.js} +6116 -6159
  13. package/dist/style.css +1 -1
  14. package/module/settings/card/admin.accounts.table/index.yml +7 -7
  15. package/module/settings/card/admin.accounts.table/rules.hbs +18 -18
  16. package/module/settings/card/admin.accounts.table/users.hbs +13 -13
  17. package/module/settings/card/admin.roles.table/access.hbs +3 -3
  18. package/module/settings/card/admin.roles.table/general_info.hbs +1 -1
  19. package/module/settings/card/admin.roles.table/index.yml +21 -21
  20. package/module/settings/card/admin.roles.table/users.hbs +6 -6
  21. package/module/settings/card/admin.routes.table/general_info.hbs +13 -13
  22. package/module/settings/card/admin.routes.table/groups.hbs +11 -11
  23. package/module/settings/card/admin.routes.table/index.yml +11 -11
  24. package/module/settings/card/admin.routes.table/users.hbs +16 -16
  25. package/module/settings/card/admin.users.table/context.hbs +14 -14
  26. package/module/settings/card/admin.users.table/general_info.hbs +12 -12
  27. package/module/settings/card/admin.users.table/index.yml +22 -22
  28. package/module/settings/card/admin.users.table/last_login.hbs +9 -9
  29. package/module/settings/card/admin.users.table/logs.hbs +10 -10
  30. package/module/settings/card/admin.users.table/routes.hbs +7 -7
  31. package/module/settings/card/admin.users.table/user_roles.hbs +12 -12
  32. package/module/settings/cls/core.actions.json +17 -17
  33. package/module/settings/cls/core.scope.json +13 -13
  34. package/module/settings/cls/properties.site_status.json +13 -13
  35. package/module/settings/cls/properties.widget_status.json +13 -13
  36. package/module/settings/cls/users.user_type.json +13 -13
  37. package/module/settings/form/admin.accounts.form.json +13 -13
  38. package/module/settings/form/admin.custom_column.form.json +71 -71
  39. package/module/settings/form/admin.properties.form.json +15 -15
  40. package/module/settings/form/admin.roles.form.json +21 -21
  41. package/module/settings/form/admin.routes.form.json +25 -25
  42. package/module/settings/form/admin.rules.form.json +30 -30
  43. package/module/settings/form/admin.user_properties.form.json +15 -15
  44. package/module/settings/form/admin.user_roles.form.json +13 -13
  45. package/module/settings/form/admin.user_roles_card.form.json +13 -13
  46. package/module/settings/form/admin.users.form.json +153 -153
  47. package/module/settings/form/context.account_grants.form.json +23 -23
  48. package/module/settings/form/context.account_users.form.json +12 -12
  49. package/module/settings/form/user.user_roles.form.json +13 -13
  50. package/module/settings/interface/admin.properties.json +4 -4
  51. package/module/settings/interface/admin.roles.json +4 -4
  52. package/module/settings/interface/admin.routes.json +4 -4
  53. package/module/settings/interface/admin.users.json +4 -4
  54. package/module/settings/menu.json +84 -84
  55. package/module/settings/select/core.routes.sql +1 -1
  56. package/module/settings/select/core.user_mentioned.sql +1 -1
  57. package/module/settings/select/core.user_uid.sql +1 -1
  58. package/module/settings/table/admin.accounts.table.json +42 -42
  59. package/module/settings/table/admin.custom_column.table.json +99 -99
  60. package/module/settings/table/admin.properties.table.json +39 -39
  61. package/module/settings/table/admin.roles.table.json +64 -64
  62. package/module/settings/table/admin.routes.table.json +73 -73
  63. package/module/settings/table/admin.rules.table.json +76 -76
  64. package/module/settings/table/admin.user_properties.table.json +34 -34
  65. package/module/settings/table/admin.user_roles.table.json +72 -72
  66. package/module/settings/table/admin.users.table.json +132 -132
  67. package/module/settings/table/context.account_grants.table.json +67 -67
  68. package/module/settings/table/context.account_users.table.json +37 -37
  69. package/package.json +83 -83
  70. package/plugin.js +29 -29
  71. package/server/helpers/core/badge.js +16 -16
  72. package/server/helpers/core/buttonHelper.js +21 -21
  73. package/server/helpers/core/select.js +48 -48
  74. package/server/helpers/core/token.js +18 -18
  75. package/server/helpers/index.js +29 -28
  76. package/server/helpers/list/buttonHelper.js +21 -21
  77. package/server/helpers/list/descriptionList.js +43 -43
  78. package/server/helpers/list/tableList.js +81 -81
  79. package/server/helpers/list/utils/button.js +5 -5
  80. package/server/helpers/temp/contentList.js +58 -58
  81. package/server/helpers/temp/ifCond.js +101 -101
  82. package/server/helpers/utils/button.js +5 -5
  83. package/server/helpers/utils/buttonAdd.js +5 -5
  84. package/server/helpers/utils/buttonDel.js +5 -5
  85. package/server/helpers/utils/buttonEdit.js +5 -5
  86. package/server/plugins/access/funcs/getAdminAccess.js +12 -12
  87. package/server/plugins/access/index.mjs +6 -6
  88. package/server/plugins/adminHook.js +81 -81
  89. package/server/plugins/cron.js +10 -10
  90. package/server/plugins/docs.js +28 -28
  91. package/server/plugins/hook.js +236 -230
  92. package/server/plugins/vite.js +71 -71
  93. package/server/routes/access/controllers/access.group.js +29 -29
  94. package/server/routes/access/controllers/access.group.post.js +49 -49
  95. package/server/routes/access/index.mjs +8 -8
  96. package/server/routes/access/schema.mjs +57 -57
  97. package/server/routes/calendar/controllers/calendar.data.js +87 -87
  98. package/server/routes/calendar/index.mjs +7 -7
  99. package/server/routes/calendar/schema.js +21 -21
  100. package/server/routes/data/controllers/cardData.js +105 -105
  101. package/server/routes/data/controllers/cardTabData.js +49 -49
  102. package/server/routes/data/controllers/funcs/getFilterSQL/index.js +92 -92
  103. package/server/routes/data/controllers/funcs/getFilterSQL/util/formatValue.js +170 -170
  104. package/server/routes/data/controllers/funcs/getFilterSQL/util/getCustomQuery.js +13 -13
  105. package/server/routes/data/controllers/funcs/getFilterSQL/util/getFilterQuery.js +64 -64
  106. package/server/routes/data/controllers/funcs/getFilterSQL/util/getOptimizedQuery.js +12 -12
  107. package/server/routes/data/controllers/funcs/getFilterSQL/util/getTableSql.js +34 -34
  108. package/server/routes/data/controllers/tableData.js +29 -29
  109. package/server/routes/data/controllers/tableDataId.js +27 -27
  110. package/server/routes/data/controllers/tableFilter.js +67 -67
  111. package/server/routes/data/controllers/tokenInfo.js +9 -9
  112. package/server/routes/data/controllers/utils/assignTokens.js +30 -30
  113. package/server/routes/data/controllers/utils/conditions.js +20 -20
  114. package/server/routes/data/controllers/utils/getColumns.js +8 -8
  115. package/server/routes/data/index.mjs +17 -17
  116. package/server/routes/data/schema.js +54 -54
  117. package/server/routes/menu/controllers/getMenu.js +58 -58
  118. package/server/routes/menu/index.mjs +5 -5
  119. package/server/routes/notifications/controllers/readNotifications.js +27 -27
  120. package/server/routes/notifications/controllers/testEmail.js +35 -35
  121. package/server/routes/notifications/controllers/userNotifications.js +53 -53
  122. package/server/routes/notifications/funcs/addNotification.js +21 -21
  123. package/server/routes/notifications/funcs/sendNotification.js +92 -92
  124. package/server/routes/notifications/hook/onWidgetSet.js +57 -57
  125. package/server/routes/notifications/index.mjs +27 -27
  126. package/server/routes/notifications/schema.js +16 -16
  127. package/server/routes/properties/controllers/admin.properties.get.js +29 -29
  128. package/server/routes/properties/controllers/user.properties.get.js +30 -30
  129. package/server/routes/properties/controllers/user.properties.post.js +30 -30
  130. package/server/routes/properties/funcs/getSettings.js +56 -56
  131. package/server/routes/properties/funcs/setSettings.js +44 -44
  132. package/server/routes/properties/funcs/utils/dataInsert.js +26 -26
  133. package/server/routes/properties/index.mjs +14 -14
  134. package/server/routes/properties/schema.js +10 -10
  135. package/server/routes/root.mjs +3 -3
  136. package/server/routes/templates/controllers/getTemplate.js +43 -41
  137. package/server/routes/templates/index.mjs +16 -16
  138. package/server/routes/templates/schema.js +8 -8
  139. package/server/routes/user/controllers/user.cls.id.js +14 -14
  140. package/server/routes/user/controllers/user.cls.js +71 -71
  141. package/server/routes/user/controllers/user.cls.post.js +52 -52
  142. package/server/routes/user/controllers/user.info.js +17 -17
  143. package/server/routes/user/schema.js +14 -14
  144. package/server/routes/widget/controllers/utils/historyFormat.js +75 -75
  145. package/server/routes/widget/controllers/utils/obj2db.js +13 -13
  146. package/server/routes/widget/controllers/widget.del.js +41 -41
  147. package/server/routes/widget/controllers/widget.get.js +96 -96
  148. package/server/routes/widget/controllers/widget.set.js +76 -76
  149. package/server/routes/widget/index.mjs +11 -11
  150. package/server/routes/widget/schema.js +12 -12
  151. package/server/templates/cls/itree.recrzone_category.json +73 -73
  152. package/server/templates/cls/test.json +9 -9
  153. package/server/templates/form/admin.user_cls.data.form.json +49 -49
  154. package/server/templates/form/admin.user_group_rel.form.json +21 -21
  155. package/server/templates/form/cp_building.form.json +32 -32
  156. package/server/templates/form/form-user-pass.json +10 -10
  157. package/server/templates/form/form-user_group.json +39 -39
  158. package/server/templates/form/form-users.json +156 -156
  159. package/server/templates/form/user_group_access.form.json +22 -22
  160. package/server/templates/select/account_id.json +2 -2
  161. package/server/templates/table/gis.dataset.table.json +43 -43
  162. package/server/templates/table/management.user_group.table.json +112 -112
  163. package/server/templates/table/management.users.table.json +126 -126
  164. package/utils.js +29 -29
@@ -1,231 +1,237 @@
1
- import path from 'node:path';
2
-
3
- import {
4
- getTemplatePath, addHook, getToken, getTemplate, config, pgClients,
5
- initPG,
6
- } from '@opengis/fastify-table/utils.js';
7
-
8
- import getMenu from '../routes/menu/controllers/getMenu.js';
9
-
10
- const { client } = pgClients;
11
-
12
- export default async function plugin(fastify) {
13
- const user1 = config?.auth?.disable || process.env.NODE_ENV !== 'admin' ? { uid: '1' } : null;
14
- await initPG(client);
15
-
16
- fastify.addHook('onListen', async () => {
17
- const json = await getMenu({ user: { uid: 1 } });
18
- // insert interface list to db (user access management)
19
- if (client?.pk?.['admin.routes'] && json?.length) {
20
- const menuList = json.filter((el) => (el?.table || el?.component || el?.menu?.length) && el?.ua || el?.en || el?.name);
21
-
22
- // skip dupes
23
- const q = `insert into admin.menu(name, ord) values${menuList.filter((el, idx, arr) => arr.map((el) => el?.ua || el?.en || el?.name).indexOf(el?.ua || el?.en || el?.name) === idx).map((el, i) => `('${(el?.ua || el?.en || el?.name).replace(/'/g, '’')}', ${i}) `).join(',')
24
- } on conflict (name) do update set ord=excluded.ord, enabled=true returning name, menu_id`;
25
-
26
- const { rows = [] } = menuList?.length ? await client.query(q) : {};
27
- const menus = rows.reduce((acc, curr) => Object.assign(acc, { [curr.menu_id]: menuList.find((item) => (item?.ua || item?.en || item?.name) === curr.name) }), {});
28
- const values = Object.entries(menus).reduce((acc, curr) => {
29
- if (curr[1]?.table || curr[1]?.component) { acc.push({ ...curr[1], menuId: curr[0] }); }
30
- curr[1]?.menu?.forEach((el) => acc.push({ ...el, menuId: curr[0] }));
31
- return acc;
32
- }, []);
33
-
34
- await Promise.all(values.filter((el) => el?.table).map(async (el) => {
35
- const loadTable = await getTemplate('table', el.table);
36
- Object.assign(el, {
37
- table1: loadTable?.table || el.table,
38
- actions: loadTable?.actions,
39
- access: loadTable?.access,
40
- });
41
- }));
42
-
43
- const q1 = `insert into admin.routes(route_id, alias, title, menu_id, table_name, actions, access, query)
44
- values ${values.filter((el) => el?.path).map((el) => `('${el.path}', ${el.table ? `'${el.table}'` : null},
45
- ${(el.title || el.ua) ? `'${(el.title || el.ua).replace(/'/g, "''")}'` : null},
46
- ${el.menuId ? `'${el.menuId}'` : null}, ${el.table1 ? `'${el.table1}'` : null},
47
- ${el.actions?.length ? `'{ ${el.actions} }'::text[]` : null}, ${el.access ? `'${el.access}'` : null},
48
- ${el.query ? `'${el.query.replace(/'/g, "''")}'` : '\'1=1\''})`).join(',')}
49
- on conflict (route_id) do update set menu_id=excluded.menu_id, alias=excluded.alias, title=excluded.title, enabled=true, query=excluded.query,
50
- table_name=excluded.table_name, actions=excluded.actions, access=excluded.access returning route_id, table_name`;
51
-
52
- try {
53
- console.log('admin/hook routes sql start');
54
-
55
- const { rowCount: menuCount } = await client.query(`delete from admin.menu
56
- where not array[menu_id] <@ $1::text[] and menu_id not in (select menu_id from admin.routes)`, [rows.map((el) => el.menu_id)]);
57
- console.log('delete deprecated menus ok', menuCount);
58
-
59
- const { rowCount: interfaceCount } = await client.query(`delete from admin.routes
60
- where not array[route_id] <@ $1::text[] and route_id not in (select route_id from admin.role_access)`, [values.filter((el) => el?.path)]);
61
- console.log('delete deprecated interfaces ok', interfaceCount);
62
-
63
- const { rowCount } = values?.length ? await client.query(q1) : {};
64
- console.log('insert interfaces ok', rowCount);
65
- } catch (err) {
66
- console.log('admin/hook routes sql error', values, q1, err);
67
- }
68
- }
69
- });
70
-
71
- fastify.addHook('onListen', async () => {
72
- const clsQuery = [];
73
- if (!client?.pk?.['admin.cls']) return;
74
-
75
- const selectList = await getTemplatePath('select');
76
- const clsList = (await getTemplatePath('cls'))?.filter((el) => !(selectList?.map((el) => el?.[0]) || []).includes(el[0]));
77
- const cls = (selectList || []).concat(clsList || [])
78
- ?.map((el) => ({ name: el[0], module: path.basename(path.dirname(path.dirname(el[1]))), type: { 'json': 'cls', 'sql': 'select' }[el[2]] }))
79
- if (!cls?.length) return;
80
-
81
- const dupes = cls.filter((el, idx, arr) => arr.map((item) => item.name).indexOf(el.name) !== idx);
82
- //console.log('cls insert skip dupes', dupes.map((el) => el.name));
83
-
84
- try {
85
- await Promise.all(cls.filter((el, idx, arr) => arr.map((item) => item.name).indexOf(el.name) === idx).map(async (el) => {
86
- const { name, module, type } = el;
87
- const loadTemplate = await getTemplate(type, name);
88
- // console.log(name, type);
89
- if (type === 'select') {
90
- clsQuery.push(`insert into admin.cls(name,type,data,module) values('${name}','sql','${(loadTemplate?.sql || loadTemplate)?.replace(/'/g, "''")}', '${module?.replace(/'/g, "''")}')`);
91
- } else if (type === 'cls' && loadTemplate?.length) {
92
- clsQuery.push(`insert into admin.cls(name,type, module) values('${name}','json', '${module?.replace(/'/g, "''")}');
93
- insert into admin.cls(code,name,parent,icon,data)
94
- select value->>'id',value->>'text','${name}',value->>'icon',value->>'data'
95
- from json_array_elements('${JSON.stringify(loadTemplate).replace(/'/g, "''")}'::json)`);
96
- } else {
97
- console.log(name, type, 'empty');
98
- }
99
- }));
100
-
101
- await client.query('truncate admin.cls');
102
- if (clsQuery.filter((el) => el).length) {
103
- await client.query(clsQuery.filter((el) => el).join(';'));
104
- console.log('admin/hook cls sql start', clsQuery?.length);
105
- }
106
- } catch (err) {
107
- console.error('admin/hook cls sql error', err.toString());
108
- }
109
- });
110
-
111
- addHook('afterTable', async ({ table, res = {}, payload: rows = [], user = {} }) => {
112
- const loadTable = await getTemplate('table', table);
113
- const { uid } = user1 || user;
114
- if (!uid || !table || !client?.pk?.[table] || !rows.length || !loadTable?.table) return;
115
-
116
- // admin.custom_column - user column data
117
- const { rows: properties = [] } = await client.query(`select column_id, name, title, format, data from admin.custom_column
118
- where _table and entity=$1 and uid=$2`, [table, uid]);
119
- const extraColumnList = properties.map((row) => ({ id: row.column_id, name: row.name, title: row.title, format: row.format, data: row.data }));
120
- if (!extraColumnList?.length) return;
121
-
122
- if (res?.columns?.length) {
123
- extraColumnList.forEach((col) => res.columns.push(col));
124
- }
125
-
126
- const { rows: extraData = [] } = await client.query(`select object_id, json_object_agg( property_id, coalesce(value_date::text,value_text) ) as extra from crm.extra_data
127
- where property_entity=$1 and property_id=any($2) and object_id=any($3) group by object_id`, [table, extraColumnList?.map((el) => el.id), rows.map((el) => el.id)]);
128
-
129
- if (!extraData?.length) {
130
- // Object.assign(rows?.[0] || {}, { ...extraColumnList.reduce((acc, curr) => Object.assign(acc, { [curr.name]: null }), {}) });
131
- return;
132
- }
133
-
134
- rows.filter((row) => extraData.map((el) => el?.object_id).includes(row.id)).forEach((row) => {
135
- const { extra = {} } = extraData.find((el) => el.object_id === row.id);
136
- Object.assign(row, { ...Object.fromEntries(Object.entries(extra).map((el) => [extraColumnList.find((col) => col.id === el[0]).name, el[1]])) });
137
- });
138
-
139
- // admin.custom_column - metaFormat
140
- await Promise.all(extraColumnList.filter((el) => el?.data).map(async (attr) => {
141
- const values = [...new Set(rows?.map((el) => el[attr.name]).flat())].filter((el) => el);
142
- if (!values.length) return;
143
- const cls = await getSelectVal({ name: attr.data, values });
144
- if (!cls) return;
145
- rows.forEach(el => {
146
- const val = el[attr.name]?.map?.(c => cls[c] || c) || cls[el[attr.name]] || el[attr.name];
147
- if (!val) return;
148
- Object.assign(el, { [val?.color ? `${attr.name}_data` : `${attr.name}_text`]: (val.color ? val : val.text || val) });
149
- });
150
- }));
151
- });
152
-
153
- // extract table from form token for user columns - p.2 - read (refactor to global token)
154
- addHook('preTemplate', async ({ name, type, user = {} }) => {
155
- if (!name || !type) return;
156
- const { uid } = user1 || user;
157
- const tokenData = await getToken({
158
- uid, token: name, mode: 'w', json: 1,
159
- }) // edit?
160
- || await getToken({
161
- uid, token: name, mode: 'a', json: 1,
162
- }) || {}; // add?
163
- return { name: tokenData?.[type] };
164
- });
165
-
166
- addHook('afterTemplate', async ({ name, type, payload: data = {}, user = {} }) => {
167
- const { uid } = user1 || user;
168
- // extract table from form token for user columns - p.1 - assign (refactor to global token)
169
- if (!uid || !data || type !== 'form' || !name) return null;
170
-
171
- const { form, id, table } = await getToken({
172
- uid, token: name, mode: 'w', json: 1,
173
- }) // edit?
174
- || await getToken({
175
- uid, token: name, mode: 'a', json: 1,
176
- }) || {}; // add?
177
-
178
- const { rows: properties = [] } = await client.query(`select name, title, format, data from admin.custom_column
179
- where entity=$1 and uid=$2`, [table || name, uid]);
180
-
181
- await Promise.all(properties.map(async (el) => {
182
- const clsData = el.data ? await getTemplate(['cls', 'select'], el.data) : undefined;
183
- const type = clsData ? 'Select' : ({ date: 'DatePicker' }[el.format] || 'Text');
184
- Object.assign(data?.schema || data || {}, { [el.name]: { type, ua: el.title, data: el.data, options: type === 'Select' && Array.isArray(clsData) && clsData?.length ? clsData : undefined, extra: 1 } });
185
- }));
186
- });
187
-
188
- addHook('afterUpdate', async ({ table, body = {}, payload: res = {}, user = {} }) => {
189
- const { uid } = user1 || user;
190
- if (!uid || !table || !Object.keys(body)?.length) return null;
191
-
192
- const loadTable = await getTemplate('table', table);
193
- if (!client?.pk?.[loadTable?.table || table]) return null;
194
- const pk = client?.pk?.[loadTable?.table || table];
195
- const id = res[pk];
196
-
197
- const { rows: properties = [] } = await client.query(`select column_id, name, title, format, data from admin.custom_column
198
- where entity=$1 and uid=$2`, [table, uid]);
199
-
200
- if (!id || !properties?.length) return null;
201
-
202
- const q = `delete from crm.extra_data where property_entity='${table}' and object_id='${id}';${properties
203
- .filter((el) => Object.keys(body).includes(el.name))
204
- .map((el) => `insert into crm.extra_data(property_id,property_key,property_entity,object_id,${el.format?.toLowerCase() === 'date' ? 'value_date' : 'value_text'})
205
- select '${el.column_id}', '${el.name}', '${table}', '${id}', ${el.format?.toLowerCase() === 'date' ? `'${body[el.name]}'::timestamp without time zone` : `'${body[el.name]}'::text`}`)
206
- .join(';\n') || ''}`;
207
- return client.query(q);
208
- });
209
-
210
- addHook('afterInsert', async ({ table, body = {}, payload: res = {}, user = {} }) => {
211
- const { uid } = user1 || user;
212
- if (!uid || !table || !Object.keys(body)?.length) return null;
213
-
214
- const loadTable = await getTemplate('table', table);
215
- if (!client?.pk?.[loadTable?.table || table]) return null;
216
- const pk = client?.pk?.[loadTable?.table || table];
217
- const id = res.rows?.[0]?.[pk];
218
-
219
- const { rows: properties = [] } = await client.query(`select column_id, name, title, format, data from admin.custom_column
220
- where entity=$1 and uid=$2`, [table, uid]);
221
-
222
- if (!id || !properties?.length) return null;
223
-
224
- const q = properties
225
- .filter((el) => Object.keys(body).includes(el.name))
226
- .map((el) => `insert into crm.extra_data(property_id,property_key,property_entity,object_id,${el.format?.toLowerCase() === 'date' ? 'value_date' : 'value_text'})
227
- select '${el.column_id}', '${el.name}', '${table}', '${id}', ${el.format?.toLowerCase() === 'date' ? `'${body[el.name]}'::timestamp without time zone` : `'${body[el.name]}'::text`}`)
228
- .join(';\n');
229
- return client.query(q);
230
- });
1
+ import path from 'node:path';
2
+
3
+ import {
4
+ getTemplatePath, addHook, getToken, getTemplate, config, pgClients,
5
+ initPG,
6
+ } from '@opengis/fastify-table/utils.js';
7
+
8
+ import getMenu from '../routes/menu/controllers/getMenu.js';
9
+
10
+ const { client } = pgClients;
11
+
12
+ export default async function plugin(fastify) {
13
+ const user1 = config?.auth?.disable || process.env.NODE_ENV !== 'admin' ? { uid: '1' } : null;
14
+ await initPG(client);
15
+
16
+ addHook('preForm', async ({ form, user }) => {
17
+ if (!user?.uid) return null;
18
+ const opt = await getToken({ mode: 'w', token: form, uid: user.uid, json: 1 });
19
+ return opt;
20
+ });
21
+
22
+ fastify.addHook('onListen', async () => {
23
+ const json = await getMenu({ user: { uid: 1 } });
24
+ // insert interface list to db (user access management)
25
+ if (client?.pk?.['admin.routes'] && json?.length) {
26
+ const menuList = json.filter((el) => (el?.table || el?.component || el?.menu?.length) && el?.ua || el?.en || el?.name);
27
+
28
+ // skip dupes
29
+ const q = `insert into admin.menu(name, ord) values${menuList.filter((el, idx, arr) => arr.map((el) => el?.ua || el?.en || el?.name).indexOf(el?.ua || el?.en || el?.name) === idx).map((el, i) => `('${(el?.ua || el?.en || el?.name).replace(/'/g, '’')}', ${i}) `).join(',')
30
+ } on conflict (name) do update set ord=excluded.ord, enabled=true returning name, menu_id`;
31
+
32
+ const { rows = [] } = menuList?.length ? await client.query(q) : {};
33
+ const menus = rows.reduce((acc, curr) => Object.assign(acc, { [curr.menu_id]: menuList.find((item) => (item?.ua || item?.en || item?.name) === curr.name) }), {});
34
+ const values = Object.entries(menus).reduce((acc, curr) => {
35
+ if (curr[1]?.table || curr[1]?.component) { acc.push({ ...curr[1], menuId: curr[0] }); }
36
+ curr[1]?.menu?.forEach((el) => acc.push({ ...el, menuId: curr[0] }));
37
+ return acc;
38
+ }, []);
39
+
40
+ await Promise.all(values.filter((el) => el?.table).map(async (el) => {
41
+ const loadTable = await getTemplate('table', el.table);
42
+ Object.assign(el, {
43
+ table1: loadTable?.table || el.table,
44
+ actions: loadTable?.actions,
45
+ access: loadTable?.access,
46
+ });
47
+ }));
48
+
49
+ const q1 = `insert into admin.routes(route_id, alias, title, menu_id, table_name, actions, access, query)
50
+ values ${values.filter((el) => el?.path).map((el) => `('${el.path}', ${el.table ? `'${el.table}'` : null},
51
+ ${(el.title || el.ua) ? `'${(el.title || el.ua).replace(/'/g, "''")}'` : null},
52
+ ${el.menuId ? `'${el.menuId}'` : null}, ${el.table1 ? `'${el.table1}'` : null},
53
+ ${el.actions?.length ? `'{ ${el.actions} }'::text[]` : null}, ${el.access ? `'${el.access}'` : null},
54
+ ${el.query ? `'${el.query.replace(/'/g, "''")}'` : '\'1=1\''})`).join(',')}
55
+ on conflict (route_id) do update set menu_id=excluded.menu_id, alias=excluded.alias, title=excluded.title, enabled=true, query=excluded.query,
56
+ table_name=excluded.table_name, actions=excluded.actions, access=excluded.access returning route_id, table_name`;
57
+
58
+ try {
59
+ console.log('admin/hook routes sql start');
60
+
61
+ const { rowCount: menuCount } = await client.query(`delete from admin.menu
62
+ where not array[menu_id] <@ $1::text[] and menu_id not in (select menu_id from admin.routes)`, [rows.map((el) => el.menu_id)]);
63
+ console.log('delete deprecated menus ok', menuCount);
64
+
65
+ const { rowCount: interfaceCount } = await client.query(`delete from admin.routes
66
+ where not array[route_id] <@ $1::text[] and route_id not in (select route_id from admin.role_access)`, [values.filter((el) => el?.path)]);
67
+ console.log('delete deprecated interfaces ok', interfaceCount);
68
+
69
+ const { rowCount } = values?.length ? await client.query(q1) : {};
70
+ console.log('insert interfaces ok', rowCount);
71
+ } catch (err) {
72
+ console.log('admin/hook routes sql error', values, q1, err);
73
+ }
74
+ }
75
+ });
76
+
77
+ fastify.addHook('onListen', async () => {
78
+ const clsQuery = [];
79
+ if (!client?.pk?.['admin.cls']) return;
80
+
81
+ const selectList = await getTemplatePath('select');
82
+ const clsList = (await getTemplatePath('cls'))?.filter((el) => !(selectList?.map((el) => el?.[0]) || []).includes(el[0]));
83
+ const cls = (selectList || []).concat(clsList || [])
84
+ ?.map((el) => ({ name: el[0], module: path.basename(path.dirname(path.dirname(el[1]))), type: { 'json': 'cls', 'sql': 'select' }[el[2]] }))
85
+ if (!cls?.length) return;
86
+
87
+ const dupes = cls.filter((el, idx, arr) => arr.map((item) => item.name).indexOf(el.name) !== idx);
88
+ //console.log('cls insert skip dupes', dupes.map((el) => el.name));
89
+
90
+ try {
91
+ await Promise.all(cls.filter((el, idx, arr) => arr.map((item) => item.name).indexOf(el.name) === idx).map(async (el) => {
92
+ const { name, module, type } = el;
93
+ const loadTemplate = await getTemplate(type, name);
94
+ // console.log(name, type);
95
+ if (type === 'select') {
96
+ clsQuery.push(`insert into admin.cls(name,type,data,module) values('${name}','sql','${(loadTemplate?.sql || loadTemplate)?.replace(/'/g, "''")}', '${module?.replace(/'/g, "''")}')`);
97
+ } else if (type === 'cls' && loadTemplate?.length) {
98
+ clsQuery.push(`insert into admin.cls(name,type, module) values('${name}','json', '${module?.replace(/'/g, "''")}');
99
+ insert into admin.cls(code,name,parent,icon,data)
100
+ select value->>'id',value->>'text','${name}',value->>'icon',value->>'data'
101
+ from json_array_elements('${JSON.stringify(loadTemplate).replace(/'/g, "''")}'::json)`);
102
+ } else {
103
+ console.log(name, type, 'empty');
104
+ }
105
+ }));
106
+
107
+ await client.query('truncate admin.cls');
108
+ if (clsQuery.filter((el) => el).length) {
109
+ await client.query(clsQuery.filter((el) => el).join(';'));
110
+ console.log('admin/hook cls sql start', clsQuery?.length);
111
+ }
112
+ } catch (err) {
113
+ console.error('admin/hook cls sql error', err.toString());
114
+ }
115
+ });
116
+
117
+ addHook('afterTable', async ({ table, res = {}, payload: rows = [], user = {} }) => {
118
+ const loadTable = await getTemplate('table', table);
119
+ const { uid } = user1 || user;
120
+ if (!uid || !table || !client?.pk?.[table] || !rows.length || !loadTable?.table) return;
121
+
122
+ // admin.custom_column - user column data
123
+ const { rows: properties = [] } = await client.query(`select column_id, name, title, format, data from admin.custom_column
124
+ where _table and entity=$1 and uid=$2`, [table, uid]);
125
+ const extraColumnList = properties.map((row) => ({ id: row.column_id, name: row.name, title: row.title, format: row.format, data: row.data }));
126
+ if (!extraColumnList?.length) return;
127
+
128
+ if (res?.columns?.length) {
129
+ extraColumnList.forEach((col) => res.columns.push(col));
130
+ }
131
+
132
+ const { rows: extraData = [] } = await client.query(`select object_id, json_object_agg( property_id, coalesce(value_date::text,value_text) ) as extra from crm.extra_data
133
+ where property_entity=$1 and property_id=any($2) and object_id=any($3) group by object_id`, [table, extraColumnList?.map((el) => el.id), rows.map((el) => el.id)]);
134
+
135
+ if (!extraData?.length) {
136
+ // Object.assign(rows?.[0] || {}, { ...extraColumnList.reduce((acc, curr) => Object.assign(acc, { [curr.name]: null }), {}) });
137
+ return;
138
+ }
139
+
140
+ rows.filter((row) => extraData.map((el) => el?.object_id).includes(row.id)).forEach((row) => {
141
+ const { extra = {} } = extraData.find((el) => el.object_id === row.id);
142
+ Object.assign(row, { ...Object.fromEntries(Object.entries(extra).map((el) => [extraColumnList.find((col) => col.id === el[0]).name, el[1]])) });
143
+ });
144
+
145
+ // admin.custom_column - metaFormat
146
+ await Promise.all(extraColumnList.filter((el) => el?.data).map(async (attr) => {
147
+ const values = [...new Set(rows?.map((el) => el[attr.name]).flat())].filter((el) => el);
148
+ if (!values.length) return;
149
+ const cls = await getSelectVal({ name: attr.data, values });
150
+ if (!cls) return;
151
+ rows.forEach(el => {
152
+ const val = el[attr.name]?.map?.(c => cls[c] || c) || cls[el[attr.name]] || el[attr.name];
153
+ if (!val) return;
154
+ Object.assign(el, { [val?.color ? `${attr.name}_data` : `${attr.name}_text`]: (val.color ? val : val.text || val) });
155
+ });
156
+ }));
157
+ });
158
+
159
+ // extract table from form token for user columns - p.2 - read (refactor to global token)
160
+ addHook('preTemplate', async ({ name, type, user = {} }) => {
161
+ if (!name || !type) return;
162
+ const { uid } = user1 || user;
163
+ const tokenData = await getToken({
164
+ uid, token: name, mode: 'w', json: 1,
165
+ }) // edit?
166
+ || await getToken({
167
+ uid, token: name, mode: 'a', json: 1,
168
+ }) || {}; // add?
169
+ return { name: tokenData?.[type] };
170
+ });
171
+
172
+ addHook('afterTemplate', async ({ name, type, payload: data = {}, user = {} }) => {
173
+ const { uid } = user1 || user;
174
+ // extract table from form token for user columns - p.1 - assign (refactor to global token)
175
+ if (!uid || !data || type !== 'form' || !name) return null;
176
+
177
+ const { form, id, table } = await getToken({
178
+ uid, token: name, mode: 'w', json: 1,
179
+ }) // edit?
180
+ || await getToken({
181
+ uid, token: name, mode: 'a', json: 1,
182
+ }) || {}; // add?
183
+
184
+ const { rows: properties = [] } = await client.query(`select name, title, format, data from admin.custom_column
185
+ where entity=$1 and uid=$2`, [table || name, uid]);
186
+
187
+ await Promise.all(properties.map(async (el) => {
188
+ const clsData = el.data ? await getTemplate(['cls', 'select'], el.data) : undefined;
189
+ const type = clsData ? 'Select' : ({ date: 'DatePicker' }[el.format] || 'Text');
190
+ Object.assign(data?.schema || data || {}, { [el.name]: { type, ua: el.title, data: el.data, options: type === 'Select' && Array.isArray(clsData) && clsData?.length ? clsData : undefined, extra: 1 } });
191
+ }));
192
+ });
193
+
194
+ addHook('afterUpdate', async ({ table, body = {}, payload: res = {}, user = {} }) => {
195
+ const { uid } = user1 || user;
196
+ if (!uid || !table || !Object.keys(body)?.length) return null;
197
+
198
+ const loadTable = await getTemplate('table', table);
199
+ if (!client?.pk?.[loadTable?.table || table]) return null;
200
+ const pk = client?.pk?.[loadTable?.table || table];
201
+ const id = res[pk];
202
+
203
+ const { rows: properties = [] } = await client.query(`select column_id, name, title, format, data from admin.custom_column
204
+ where entity=$1 and uid=$2`, [table, uid]);
205
+
206
+ if (!id || !properties?.length) return null;
207
+
208
+ const q = `delete from crm.extra_data where property_entity='${table}' and object_id='${id}';${properties
209
+ .filter((el) => Object.keys(body).includes(el.name))
210
+ .map((el) => `insert into crm.extra_data(property_id,property_key,property_entity,object_id,${el.format?.toLowerCase() === 'date' ? 'value_date' : 'value_text'})
211
+ select '${el.column_id}', '${el.name}', '${table}', '${id}', ${el.format?.toLowerCase() === 'date' ? `'${body[el.name]}'::timestamp without time zone` : `'${body[el.name]}'::text`}`)
212
+ .join(';\n') || ''}`;
213
+ return client.query(q);
214
+ });
215
+
216
+ addHook('afterInsert', async ({ table, body = {}, payload: res = {}, user = {} }) => {
217
+ const { uid } = user1 || user;
218
+ if (!uid || !table || !Object.keys(body)?.length) return null;
219
+
220
+ const loadTable = await getTemplate('table', table);
221
+ if (!client?.pk?.[loadTable?.table || table]) return null;
222
+ const pk = client?.pk?.[loadTable?.table || table];
223
+ const id = res.rows?.[0]?.[pk];
224
+
225
+ const { rows: properties = [] } = await client.query(`select column_id, name, title, format, data from admin.custom_column
226
+ where entity=$1 and uid=$2`, [table, uid]);
227
+
228
+ if (!id || !properties?.length) return null;
229
+
230
+ const q = properties
231
+ .filter((el) => Object.keys(body).includes(el.name))
232
+ .map((el) => `insert into crm.extra_data(property_id,property_key,property_entity,object_id,${el.format?.toLowerCase() === 'date' ? 'value_date' : 'value_text'})
233
+ select '${el.column_id}', '${el.name}', '${table}', '${id}', ${el.format?.toLowerCase() === 'date' ? `'${body[el.name]}'::timestamp without time zone` : `'${body[el.name]}'::text`}`)
234
+ .join(';\n');
235
+ return client.query(q);
236
+ });
231
237
  }