@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.
- package/.eslintrc.cjs +42 -42
- package/Changelog.md +52 -47
- package/README.md +26 -26
- package/config.js +11 -11
- package/crud/controllers/deleteCrud.js +14 -14
- package/crud/controllers/insert.js +29 -29
- package/crud/controllers/update.js +31 -31
- package/crud/controllers/utils/checkXSS.js +45 -45
- package/crud/controllers/utils/xssInjection.js +72 -72
- package/crud/funcs/dataDelete.js +15 -15
- package/crud/funcs/dataInsert.js +24 -24
- package/crud/funcs/dataUpdate.js +20 -20
- package/crud/funcs/getToken.js +27 -27
- package/crud/funcs/isFileExists.js +13 -13
- package/crud/funcs/setToken.js +53 -53
- package/crud/index.js +29 -29
- package/helper.js +28 -28
- package/index.js +4 -0
- package/notification/controllers/userNotifications.js +19 -0
- package/notification/funcs/addNotification.js +8 -0
- package/notification/index.js +19 -0
- package/package.json +22 -22
- package/pg/funcs/autoIndex.js +89 -89
- package/pg/funcs/getMeta.js +27 -27
- package/pg/funcs/getPG.js +29 -29
- package/pg/funcs/init.js +42 -42
- package/pg/funcs/pgClients.js +2 -2
- package/pg/index.js +35 -35
- package/pg/pgClients.js +20 -20
- package/policy/funcs/checkPolicy.js +74 -74
- package/policy/funcs/sqlInjection.js +33 -33
- package/policy/index.js +14 -14
- package/redis/client.js +8 -8
- package/redis/funcs/getRedis.js +23 -23
- package/redis/funcs/redisClients.js +2 -2
- package/redis/index.js +19 -19
- package/server/migrations/crm.sql +55 -0
- package/server/migrations/log.sql +40 -0
- package/server/templates/form/test.dataset.form.json +411 -411
- package/server.js +14 -14
- package/table/controllers/data.js +57 -57
- package/table/controllers/filter.js +32 -32
- package/table/controllers/form.js +10 -10
- package/table/controllers/suggest.js +60 -60
- package/table/controllers/utils/getSelect.js +20 -20
- package/table/controllers/utils/getSelectMeta.js +66 -66
- package/table/funcs/getFilterSQL/index.js +75 -75
- package/table/funcs/getFilterSQL/util/formatValue.js +142 -142
- package/table/funcs/getFilterSQL/util/getCustomQuery.js +13 -13
- package/table/funcs/getFilterSQL/util/getFilterQuery.js +73 -73
- package/table/funcs/getFilterSQL/util/getOptimizedQuery.js +12 -12
- package/table/funcs/getFilterSQL/util/getTableSql.js +34 -34
- package/table/funcs/metaFormat/getSelectVal.js +20 -20
- package/table/funcs/metaFormat/index.js +26 -26
- package/table/index.js +25 -25
- package/test/api/crud.test.js +50 -50
- package/test/api/crud.xss.test.js +68 -68
- package/test/api/notification.test.js +56 -0
- package/test/api/table.test.js +49 -49
- package/test/config.example +18 -18
- package/test/funcs/crud.test.js +76 -76
- package/test/funcs/pg.test.js +34 -34
- package/test/funcs/redis.test.js +19 -19
- package/test/templates/cls/test.json +9 -9
- package/test/templates/form/cp_building.form.json +32 -32
- package/test/templates/select/account_id.json +3 -3
- package/test/templates/select/storage.data.json +2 -2
- package/test/templates/table/gis.dataset.table.json +20 -20
- package/test/widget.test.js +39 -0
- package/widget/controllers/utils/obj2db.js +13 -0
- package/widget/controllers/widget.del.js +41 -0
- package/widget/controllers/widget.get.js +145 -0
- package/widget/controllers/widget.set.js +49 -0
- package/widget/index.js +38 -0
package/test/funcs/crud.test.js
CHANGED
|
@@ -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
|
+
});
|
package/test/funcs/pg.test.js
CHANGED
|
@@ -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
|
+
});
|
package/test/funcs/redis.test.js
CHANGED
|
@@ -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
|
+
}
|