@opengis/fastify-table 1.0.16 → 1.0.18

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 (74) hide show
  1. package/.eslintrc.cjs +42 -42
  2. package/Changelog.md +52 -47
  3. package/README.md +26 -26
  4. package/config.js +11 -11
  5. package/crud/controllers/deleteCrud.js +14 -14
  6. package/crud/controllers/insert.js +29 -29
  7. package/crud/controllers/update.js +31 -31
  8. package/crud/controllers/utils/checkXSS.js +45 -45
  9. package/crud/controllers/utils/xssInjection.js +72 -72
  10. package/crud/funcs/dataDelete.js +15 -15
  11. package/crud/funcs/dataInsert.js +24 -24
  12. package/crud/funcs/dataUpdate.js +20 -20
  13. package/crud/funcs/getToken.js +27 -27
  14. package/crud/funcs/isFileExists.js +13 -13
  15. package/crud/funcs/setToken.js +53 -53
  16. package/crud/index.js +29 -29
  17. package/helper.js +28 -28
  18. package/index.js +4 -0
  19. package/notification/controllers/userNotifications.js +19 -0
  20. package/notification/funcs/addNotification.js +8 -0
  21. package/notification/index.js +19 -0
  22. package/package.json +22 -22
  23. package/pg/funcs/autoIndex.js +89 -89
  24. package/pg/funcs/getMeta.js +27 -27
  25. package/pg/funcs/getPG.js +29 -29
  26. package/pg/funcs/init.js +42 -42
  27. package/pg/funcs/pgClients.js +2 -2
  28. package/pg/index.js +35 -35
  29. package/pg/pgClients.js +20 -20
  30. package/policy/funcs/checkPolicy.js +74 -74
  31. package/policy/funcs/sqlInjection.js +33 -33
  32. package/policy/index.js +14 -14
  33. package/redis/client.js +8 -8
  34. package/redis/funcs/getRedis.js +23 -23
  35. package/redis/funcs/redisClients.js +2 -2
  36. package/redis/index.js +19 -19
  37. package/server/migrations/crm.sql +55 -0
  38. package/server/migrations/log.sql +40 -0
  39. package/server/templates/form/test.dataset.form.json +411 -411
  40. package/server.js +14 -14
  41. package/table/controllers/data.js +57 -57
  42. package/table/controllers/filter.js +32 -32
  43. package/table/controllers/form.js +10 -10
  44. package/table/controllers/suggest.js +60 -60
  45. package/table/controllers/utils/getSelect.js +20 -20
  46. package/table/controllers/utils/getSelectMeta.js +66 -66
  47. package/table/funcs/getFilterSQL/index.js +75 -75
  48. package/table/funcs/getFilterSQL/util/formatValue.js +142 -142
  49. package/table/funcs/getFilterSQL/util/getCustomQuery.js +13 -13
  50. package/table/funcs/getFilterSQL/util/getFilterQuery.js +73 -73
  51. package/table/funcs/getFilterSQL/util/getOptimizedQuery.js +12 -12
  52. package/table/funcs/getFilterSQL/util/getTableSql.js +34 -34
  53. package/table/funcs/metaFormat/getSelectVal.js +20 -20
  54. package/table/funcs/metaFormat/index.js +26 -26
  55. package/table/index.js +25 -25
  56. package/test/api/crud.test.js +50 -50
  57. package/test/api/crud.xss.test.js +68 -68
  58. package/test/api/notification.test.js +56 -0
  59. package/test/api/table.test.js +49 -49
  60. package/test/config.example +18 -18
  61. package/test/funcs/crud.test.js +76 -76
  62. package/test/funcs/pg.test.js +34 -34
  63. package/test/funcs/redis.test.js +19 -19
  64. package/test/templates/cls/test.json +9 -9
  65. package/test/templates/form/cp_building.form.json +32 -32
  66. package/test/templates/select/account_id.json +3 -3
  67. package/test/templates/select/storage.data.json +2 -2
  68. package/test/templates/table/gis.dataset.table.json +20 -20
  69. package/test/widget.test.js +39 -0
  70. package/widget/controllers/utils/obj2db.js +13 -0
  71. package/widget/controllers/widget.del.js +41 -0
  72. package/widget/controllers/widget.get.js +145 -0
  73. package/widget/controllers/widget.set.js +49 -0
  74. package/widget/index.js +38 -0
@@ -1,76 +1,76 @@
1
- import { test } from 'node:test';
2
- import assert from 'node:assert';
3
- import config from '../config.js';
4
- import pgClients from '../../pg/pgClients.js';
5
- import rclient from '../../redis/client.js';
6
-
7
- import dataInsert from '../../crud/funcs/dataInsert.js';
8
- import dataUpdate from '../../crud/funcs/dataUpdate.js';
9
- import dataDelete from '../../crud/funcs/dataDelete.js';
10
- import isFileExists from '../../crud/funcs/isFileExists.js';
11
-
12
- import getOpt from '../../crud/funcs/getOpt.js';
13
- import setOpt from '../../crud/funcs/setOpt.js';
14
-
15
- import getToken from '../../crud/funcs/getToken.js';
16
- import setToken from '../../crud/funcs/setToken.js';
17
-
18
- test('funcs crud', async (t) => {
19
- await pgClients.client.init();
20
- await t.test('getOpt/setOpt', async () => {
21
- const opt = await setOpt({ table: 'gis.dataset' });
22
- const data = await getOpt(opt);
23
- // console.log(data);
24
- assert.equal(data.table, 'gis.dataset');
25
- });
26
-
27
- const id = (Math.random() * 10000).toFixed();
28
- await t.test('dataInsert', async () => {
29
- const data = await dataInsert({ table: 'gis.dataset', data: { dataset_id: id, dataset_name: '222' } });
30
- assert.equal(data.dataset_id, id);
31
- });
32
-
33
- await t.test('dataUpdate', async () => {
34
- const data = await dataUpdate({ table: 'gis.dataset', id, data: { dataset_name: '22211' } });
35
- assert.equal(data.dataset_name, '22211');
36
- });
37
-
38
- await t.test('dataDelete', async () => {
39
- const data = await dataDelete({ table: 'gis.dataset', id });
40
- assert.ok(data);
41
- });
42
-
43
- await t.test('isFileExists', async () => {
44
- const data = await isFileExists({ filepath: '../../crud/funcs/isFileExists.js' });
45
- assert.equal(data, false);
46
- });
47
-
48
- let tokens;
49
- const session = { passport: { user: { uid: '1' } } };
50
- const tokenData = JSON.stringify({ add: 'gis.dataset', form: 'test.dataset.form' });
51
-
52
- await t.test('setToken', async () => {
53
- tokens = setToken({
54
- funcs: { config },
55
- ids: [tokenData],
56
- mode: 'a',
57
- uid: 1,
58
- array: 1,
59
- });
60
- assert.equal(tokens.length, 1);
61
- });
62
- await t.test('getToken', async () => {
63
- const data = await getToken({
64
- uid: 1,
65
- token: tokens[0],
66
- mode: 'a',
67
- });
68
- assert.equal(data, tokenData);
69
- });
70
-
71
- // pgClients.client.query('delete from gis.dataset where dataset_id=$1', [id]);
72
- t.after(() => {
73
- pgClients.client?.end();
74
- rclient.quit();
75
- });
76
- });
1
+ import { test } from 'node:test';
2
+ import assert from 'node:assert';
3
+ import config from '../config.js';
4
+ import pgClients from '../../pg/pgClients.js';
5
+ import rclient from '../../redis/client.js';
6
+
7
+ import dataInsert from '../../crud/funcs/dataInsert.js';
8
+ import dataUpdate from '../../crud/funcs/dataUpdate.js';
9
+ import dataDelete from '../../crud/funcs/dataDelete.js';
10
+ import isFileExists from '../../crud/funcs/isFileExists.js';
11
+
12
+ import getOpt from '../../crud/funcs/getOpt.js';
13
+ import setOpt from '../../crud/funcs/setOpt.js';
14
+
15
+ import getToken from '../../crud/funcs/getToken.js';
16
+ import setToken from '../../crud/funcs/setToken.js';
17
+
18
+ test('funcs crud', async (t) => {
19
+ await pgClients.client.init();
20
+ await t.test('getOpt/setOpt', async () => {
21
+ const opt = await setOpt({ table: 'gis.dataset' });
22
+ const data = await getOpt(opt);
23
+ // console.log(data);
24
+ assert.equal(data.table, 'gis.dataset');
25
+ });
26
+
27
+ const id = (Math.random() * 10000).toFixed();
28
+ await t.test('dataInsert', async () => {
29
+ const data = await dataInsert({ table: 'gis.dataset', data: { dataset_id: id, dataset_name: '222' } });
30
+ assert.equal(data.dataset_id, id);
31
+ });
32
+
33
+ await t.test('dataUpdate', async () => {
34
+ const data = await dataUpdate({ table: 'gis.dataset', id, data: { dataset_name: '22211' } });
35
+ assert.equal(data.dataset_name, '22211');
36
+ });
37
+
38
+ await t.test('dataDelete', async () => {
39
+ const data = await dataDelete({ table: 'gis.dataset', id });
40
+ assert.ok(data);
41
+ });
42
+
43
+ await t.test('isFileExists', async () => {
44
+ const data = await isFileExists({ filepath: '../../crud/funcs/isFileExists.js' });
45
+ assert.equal(data, false);
46
+ });
47
+
48
+ let tokens;
49
+ const session = { passport: { user: { uid: '1' } } };
50
+ const tokenData = JSON.stringify({ add: 'gis.dataset', form: 'test.dataset.form' });
51
+
52
+ await t.test('setToken', async () => {
53
+ tokens = setToken({
54
+ funcs: { config },
55
+ ids: [tokenData],
56
+ mode: 'a',
57
+ uid: 1,
58
+ array: 1,
59
+ });
60
+ assert.equal(tokens.length, 1);
61
+ });
62
+ await t.test('getToken', async () => {
63
+ const data = await getToken({
64
+ uid: 1,
65
+ token: tokens[0],
66
+ mode: 'a',
67
+ });
68
+ assert.equal(data, tokenData);
69
+ });
70
+
71
+ // pgClients.client.query('delete from gis.dataset where dataset_id=$1', [id]);
72
+ t.after(() => {
73
+ pgClients.client?.end();
74
+ rclient.quit();
75
+ });
76
+ });
@@ -1,34 +1,34 @@
1
- import { test } from 'node:test';
2
- import assert from 'node:assert';
3
-
4
- import '../config.js';
5
-
6
- import getMeta from '../../pg/funcs/getMeta.js';
7
- import autoIndex from '../../pg/funcs/autoIndex.js';
8
- import pgClients from '../../pg/pgClients.js';
9
- import rclient from '../../redis/client.js';
10
- // import pgClients from '../../pg/funcs/pgClients.js';
11
-
12
- test('funcs pg', async (t) => {
13
- await pgClients.client.init();
14
- await t.test('getMeta', async () => {
15
- const { columns } = await getMeta({ table: 'gis.dataset' });
16
- // console.log(columns)
17
- assert.ok(columns);
18
- });
19
-
20
- /* await t.test('getPG', async (t) => {
21
- const data = await getPG({});
22
- assert.ok(data);
23
- }); */
24
-
25
- await t.test('autoIndex', async () => {
26
- await autoIndex({ table: 'gis.dataset', columns: ['service_type'] });
27
- assert.ok(1);
28
- });
29
- t.after(() => {
30
- pgClients.client.end();
31
-
32
- rclient.quit();
33
- });
34
- });
1
+ import { test } from 'node:test';
2
+ import assert from 'node:assert';
3
+
4
+ import '../config.js';
5
+
6
+ import getMeta from '../../pg/funcs/getMeta.js';
7
+ import autoIndex from '../../pg/funcs/autoIndex.js';
8
+ import pgClients from '../../pg/pgClients.js';
9
+ import rclient from '../../redis/client.js';
10
+ // import pgClients from '../../pg/funcs/pgClients.js';
11
+
12
+ test('funcs pg', async (t) => {
13
+ await pgClients.client.init();
14
+ await t.test('getMeta', async () => {
15
+ const { columns } = await getMeta({ table: 'gis.dataset' });
16
+ // console.log(columns)
17
+ assert.ok(columns);
18
+ });
19
+
20
+ /* await t.test('getPG', async (t) => {
21
+ const data = await getPG({});
22
+ assert.ok(data);
23
+ }); */
24
+
25
+ await t.test('autoIndex', async () => {
26
+ await autoIndex({ table: 'gis.dataset', columns: ['service_type'] });
27
+ assert.ok(1);
28
+ });
29
+ t.after(() => {
30
+ pgClients.client.end();
31
+
32
+ rclient.quit();
33
+ });
34
+ });
@@ -1,19 +1,19 @@
1
- import { test } from 'node:test';
2
- import assert from 'node:assert';
3
-
4
- import '../config.js';
5
-
6
- import rclient from '../../redis/client.js';
7
-
8
- test('funcs redis', async (t) => {
9
- await t.test('get/set', async () => {
10
- await rclient.set('test', '1');
11
- const d = await rclient.get('test');
12
- // console.log(columns)
13
- assert.equal(d, '1');
14
- });
15
-
16
- t.after(() => {
17
- rclient.quit();
18
- });
19
- });
1
+ import { test } from 'node:test';
2
+ import assert from 'node:assert';
3
+
4
+ import '../config.js';
5
+
6
+ import rclient from '../../redis/client.js';
7
+
8
+ test('funcs redis', async (t) => {
9
+ await t.test('get/set', async () => {
10
+ await rclient.set('test', '1');
11
+ const d = await rclient.get('test');
12
+ // console.log(columns)
13
+ assert.equal(d, '1');
14
+ });
15
+
16
+ t.after(() => {
17
+ rclient.quit();
18
+ });
19
+ });
@@ -1,10 +1,10 @@
1
- [
2
- {
3
- "id": 1,
4
- "text": "test"
5
- },
6
- {
7
- "id": 2,
8
- "text": "test2"
9
- }
1
+ [
2
+ {
3
+ "id": 1,
4
+ "text": "test"
5
+ },
6
+ {
7
+ "id": 2,
8
+ "text": "test2"
9
+ }
10
10
  ]
@@ -1,33 +1,33 @@
1
- {
2
- "schema": {
3
-
4
- "cp_umuni_id": {
5
- "type": "Text",
6
- "ua": "ID UMUNI"
7
- },
8
- "cp_year": {
9
- "type": "Text",
10
- "ua": "Рік будівництва"
11
- },
12
- "cp_date_en_audit": {
13
- "type": "DatePicker",
14
- "ua": "Дата проведення останнього енергоаудиту"
15
- },
16
- "cp_certificate": {
17
- "type": "Text",
18
- "ua": "Сертифікат енергоефективності будівлі",
19
- "help": "Вкажіть посилання"
20
- },
21
- "cp_pkd": {
22
- "type": "Autocomplete",
23
- "data": "customer_name",
24
- "add": {
25
- "model": "crm_acc.crm_account",
26
- "ua": "Додати",
27
- "form": "account_light.form"
28
- },
29
- "ua": "Замовник ПКД"
30
- }
31
- },
32
- "label_style": "vertical"
1
+ {
2
+ "schema": {
3
+
4
+ "cp_umuni_id": {
5
+ "type": "Text",
6
+ "ua": "ID UMUNI"
7
+ },
8
+ "cp_year": {
9
+ "type": "Text",
10
+ "ua": "Рік будівництва"
11
+ },
12
+ "cp_date_en_audit": {
13
+ "type": "DatePicker",
14
+ "ua": "Дата проведення останнього енергоаудиту"
15
+ },
16
+ "cp_certificate": {
17
+ "type": "Text",
18
+ "ua": "Сертифікат енергоефективності будівлі",
19
+ "help": "Вкажіть посилання"
20
+ },
21
+ "cp_pkd": {
22
+ "type": "Autocomplete",
23
+ "data": "customer_name",
24
+ "add": {
25
+ "model": "crm_acc.crm_account",
26
+ "ua": "Додати",
27
+ "form": "account_light.form"
28
+ },
29
+ "ua": "Замовник ПКД"
30
+ }
31
+ },
32
+ "label_style": "vertical"
33
33
  }
@@ -1,4 +1,4 @@
1
- {
2
- "db": "mbk_lviv_dma",
3
- "searchColumn": "alternative_name"
1
+ {
2
+ "db": "mbk_lviv_dma",
3
+ "searchColumn": "alternative_name"
4
4
  }
@@ -1,3 +1,3 @@
1
- {
2
- "key": "dataset_id"
1
+ {
2
+ "key": "dataset_id"
3
3
  }
@@ -1,21 +1,21 @@
1
- {
2
- "columns": [
3
- {
4
- "name": "dataset_id",
5
- "title": "22"
6
- },
7
- {
8
- "name": "dataset_name",
9
- "title": "dataset_name"
10
- }
11
- ],
12
- "table": "gis.dataset",
13
- "order": "dataset_name",
14
- "filters": [
15
- {
16
- "ua": "Назва набору",
17
- "name": "dataset_name",
18
- "type": "text"
19
- }
20
- ]
1
+ {
2
+ "columns": [
3
+ {
4
+ "name": "dataset_id",
5
+ "title": "22"
6
+ },
7
+ {
8
+ "name": "dataset_name",
9
+ "title": "dataset_name"
10
+ }
11
+ ],
12
+ "table": "gis.dataset",
13
+ "order": "dataset_name",
14
+ "filters": [
15
+ {
16
+ "ua": "Назва набору",
17
+ "name": "dataset_name",
18
+ "type": "text"
19
+ }
20
+ ]
21
21
  }
@@ -0,0 +1,39 @@
1
+ import { test } from 'node:test';
2
+ import assert from 'node:assert';
3
+
4
+ import build from '../../helper.js';
5
+ import config from '../config.js';
6
+
7
+ const session = { passport: { user: { uid: config.testUser?.uid || '1' } } };
8
+
9
+ import widgetGet from '../../widget/controllers/widget.get.js';
10
+ import widgetSet from '../../widget/controllers/widget.set.js';
11
+ import widgetDel from '../../widget/controllers/widget.del.js';
12
+
13
+ import pgClients from '../../pg/pgClients.js';
14
+
15
+ test('api && funcs notification', async (t) => {
16
+ const app = await build(t);
17
+ const pg = pgClients.client;
18
+ await t.test('POST /widget/:type/:objectid', async () => {
19
+ const body = {};
20
+ const rep = await widgetSet({
21
+ pg, params: { type: 'comment', objectid: '1' }, session, body,
22
+ });
23
+ assert.ok(rep.data);
24
+ });
25
+
26
+ let resp;
27
+ await t.test('GET /widget/:type/:objectid', async () => {
28
+ resp = await widgetGet({
29
+ pg, session, params: { type: 'comment', objectid: '1' },
30
+ });
31
+ assert.ok(resp.rows.length > 0, 'widget data get fail');
32
+ });
33
+ await t.test('DELETE /widget/:type/:objectid', async () => {
34
+ resp = await widgetDel({
35
+ pg, session, params: { type: 'comment', objectid: '1', id: resp.rows?.find((row) => row)?.comment_id },
36
+ });
37
+ assert.ok(resp.data.rowCount === 1, 'widget data delete fail');
38
+ });
39
+ });
@@ -0,0 +1,13 @@
1
+ export default function obj2db(data, nonexistCol) {
2
+ if (
3
+ typeof data !== 'object'
4
+ || Array.isArray(data)
5
+ || !Object.keys(data || {}).length
6
+ ) return { error: 'invalid data type' };
7
+
8
+ const existColumns = Object.keys(data)?.filter((key) => !nonexistCol.includes(key));
9
+ const columns = existColumns?.filter((col) => data[col] || data?.[col] === 0);
10
+ const args = columns?.map((col) => data[col]);
11
+
12
+ return { columns, args, error: !columns?.length ? 'nothing to process' : undefined };
13
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Дістає CRM дані для vue хешує ідентифікатори, підтягує селекти
3
+ *
4
+ * @method DELETE
5
+ * @summary CRM дані для обраного віджета.
6
+ * @priority 2
7
+ * @tag table
8
+ * @type api
9
+ * @requires setTokenById
10
+ * @requires getSelect
11
+ * @param {String} id Ідентифікатор для хешування
12
+ * @param {Any} sql Використовується для повернення sql запиту
13
+ * @param {String} type Тип для хешування даних
14
+ * @errors 400, 500
15
+ * @returns {Number} status Номер помилки
16
+ * @returns {String|Object} error Опис помилки
17
+ * @returns {String|Object} message Повідомлення про успішне виконання або об'єкт з параметрами
18
+ */
19
+
20
+ export default async function widgetDel({
21
+ pg, params = {}, session = {},
22
+ }) {
23
+ const { user = {} } = session.passport || {};
24
+ const { type, objectid, id } = params;
25
+ if (!['comment', 'checklist', 'link', 'time'].includes(type)) return { status: 401, error: 'type not valid required' };
26
+ if (!objectid) return { error: 'id required', status: 400 };
27
+
28
+ const sql = {
29
+ comment: 'delete from crm.comment where object_id=$1 and uid=$2 and comment_id=$3',
30
+ checklist: 'delete from crm.checklist where object_id=$1 and uid=$2 and checklist_id=$3 ',
31
+ link: 'delete from crm.link where object_id=$1 and uid=$2 and link_id=$3 ',
32
+ time: 'delete from crm.elapsed_time where object_id=$1 and uid=$2 and elapsed_time_id=$3 ',
33
+ };
34
+ try {
35
+ const { rows, rowCount } = await pg.query(sql[type], [objectid, user.uid, id]);
36
+ return { data: { rows, rowCount }, user: { uid: user?.uid, name: user?.user_name } };
37
+ }
38
+ catch (err) {
39
+ return { message: err.toString(), status: 500 };
40
+ }
41
+ }
@@ -0,0 +1,145 @@
1
+ import getTemplate from '../../table/controllers/utils/getTemplate.js';
2
+ import getSelect from '../../table/controllers/utils/getSelect.js';
3
+ import getToken from '../../crud/funcs/getToken.js';
4
+ import getMeta from '../../pg/funcs/getMeta.js';
5
+ // import setToken from '../../crud/funcs/setToken.js';
6
+
7
+ const historyQ = `select nspname||'.'||relname as table_name, json_agg(json_build_object('name',attname, 'title',coalesce(col_description(attrelid, attnum),attname))) as columns
8
+ from pg_attribute a
9
+ left join pg_catalog.pg_attrdef d ON (a.attrelid, a.attnum) = (d.adrelid, d.adnum)
10
+ JOIN pg_class AS i
11
+ ON i.oid = a.attrelid
12
+ JOIN pg_namespace AS NS ON i.relnamespace = NS.OID
13
+ where a.attnum > 0
14
+ and not a.attisdropped
15
+ group by nspname||'.'||relname`;
16
+
17
+ const dbData = {};
18
+
19
+ async function historyFormat(rows, progrid, pg) {
20
+ if (!progrid) return rows;
21
+ const body = await getTemplate('table', progrid);
22
+ const tableName = body?.model || body?.table || progrid;
23
+
24
+ // get DB column description
25
+ if (!dbData?.[tableName]?.length) {
26
+ const { rows: rows1 } = await pg.query(historyQ);
27
+ rows1.forEach((row) => {
28
+ dbData[row.table_name] = row.columns;
29
+ });
30
+ }
31
+
32
+ await Promise.all(rows?.map(async (op) => {
33
+ op.changes?.map(async (el) => {
34
+ const col = body.colModel.filter((col1) => col1.name === el.attr)[0] || dbData[tableName]?.find((col1) => col1.name === el.attr);
35
+ if (el.attr === 'geom') {
36
+ el.title = 'Геометрія';
37
+ }
38
+ el.title = col?.ua || col?.title || el.attr;
39
+ if (!col) return;
40
+ el.type = col.type;
41
+ el.format = col.format;
42
+ const select = col.data || col.option || col.select;
43
+
44
+ // getSelect not equals to node
45
+ if (select && false) {
46
+ el.select = select;
47
+ const cls = await getSelect(select, {
48
+ val: [el.old, el.new],
49
+ });
50
+
51
+ el.oldf = cls[0] || el.old;
52
+ el.newf = cls[1] || el.new;
53
+ }
54
+ });
55
+ }));
56
+
57
+ return rows;
58
+ }
59
+
60
+ /**
61
+ * Дістає CRM для widget
62
+ *
63
+ */
64
+
65
+ export default async function widgetGet({
66
+ pg, session = {}, params = {}, query = {},
67
+ }) {
68
+ const { user = {} } = session.passport || {};
69
+
70
+ const param = user?.uid ? await getToken({
71
+ token: params.objectid, mode: 'w', uid: user.uid,
72
+ }) : null;
73
+
74
+ const objectid = param ? JSON.parse(param)?.id : params.objectid;
75
+
76
+ if (!['comment', 'history', 'file', 'checklist', 'link', 'time'].includes(params.type)) return { error: 'param type not valid', status: 400 };
77
+ if (!objectid) return { error: 'id required', status: 400 };
78
+
79
+ const sql = {
80
+ comment: `select body,c.cdate, comment_id,object_id,c.uid, coalesce(user_name,' ')||' '||coalesce(sur_name,'') as username,avatar
81
+ from crm.comment c left join admin.users u on u.uid=c.uid where object_id=$1 order by cdate desc`,
82
+
83
+ history1: `select _column attr, c.cdate,_old "old",_new "new", c.uid, coalesce(user_name,' ')||' '||coalesce(sur_name,'') as username,
84
+ avatar,pk_id from log.table_row_log c left join admin.users u on u.uid=c.uid where pk_id=$1 and _type='UPDATE' order by cdate desc limit 100`,
85
+
86
+ history: `SELECT operation_id, _type, c.uid, c.cdate, json_agg(json_build_object('attr',_column,'old', _old,'new', _new)) as changes, pk_id,
87
+ (select coalesce(user_name,' ')||' '||coalesce(sur_name,'') as username from admin.users u where u.uid=c.uid) username from log.table_row_log c
88
+
89
+ where pk_id=$1 and _type='UPDATE'
90
+ group by operation_id,_type,c.uid,c.cdate,c.pk_id
91
+ order by cdate desc limit 100`,
92
+
93
+ checklist: `SELECT checklist_id, title, is_done, done_date, c.uid, c.cdate, coalesce(user_name,' ')||' '||coalesce(sur_name,'') as username,
94
+ avatar FROM crm.checklist c left join admin.users u on u.uid=c.uid where object_id=$1 order by cdate desc`,
95
+
96
+ link: `SELECT link_id, link, title, meta FROM crm.link
97
+ where object_id=$1 order by cdate desc`,
98
+
99
+ time: `SELECT elapsed_time_id, time, description from crm.elapsed_time
100
+ where object_id=$1 order by cdate desc `,
101
+
102
+ file: `SELECT file_id, file_path, uploaded_name, ext, size, c.uid, c.cdate, file_type, c.main,
103
+ coalesce(user_name,' ')||' '||coalesce(sur_name,'') as username, verif,
104
+ avatar, c.author,publicate,doc_date,describe, cls_type
105
+ FROM admin.doc_file c left join admin.users u on u.uid=c.uid where object_id=$1 and file_status<>3 order by cdate desc`,
106
+
107
+ };
108
+ try {
109
+ /* data */
110
+ const time = [Date.now()];
111
+ const { rows } = await pg.query(sql[params.type], [objectid]);
112
+ time.push(Date.now());
113
+
114
+ /* Object info */
115
+ const { tableName } = await pg.one(`select _table as "tableName",pk_id from log.table_row_log c
116
+ where pk_id = $1 /*and _type ='INSERT'*/ limit 1`, [objectid]);
117
+ const { pk } = await getMeta({ table: tableName });
118
+ const q = `select coalesce(b.user_name,'')||coalesce(' '||b.sur_name,'') as author, a.cdate, a.editor_date
119
+ from ${tableName} a left join admin.users b on a.uid=b.uid where a.${pk}=$1 limit 1`;
120
+ const data = pk ? await pg.one(q, [objectid]) : {};
121
+ if (query.debug && user?.user_type === 'admin') {
122
+ return {
123
+ sql, type: params.type, q, id: objectid, data,
124
+ };
125
+ }
126
+
127
+ const progrid = null; /* tableName ? table || Object.keys(db.progrid)
128
+ .filter((el) => db.progrid[el]?.model === tableName || db.progrid[el]?.includes?.(`"${tableName}"`))[0] : null; */
129
+
130
+ time.push(Date.now());
131
+ return {
132
+ progrid,
133
+ time: { data: time[1] - time[0], format: time[2] - time[1] },
134
+ rows: params.type === 'history' ? await historyFormat(rows, progrid, pg) : rows,
135
+ user: { uid: user?.uid, name: user?.user_name },
136
+ data: { author: data?.author, cdate: data?.cdate, edate: data?.editor_date },
137
+ objectid: params.objectid,
138
+ };
139
+ }
140
+ catch (err) {
141
+ // 'history', 'file', 'checklist'
142
+ /* 'document', 'image' - Макс на клиенте */
143
+ return { message: err.toString(), status: 500 };
144
+ }
145
+ }