@opengis/fastify-table 1.0.20 → 1.0.22
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/Changelog.md +8 -0
- package/dblist/controllers/deleteItem.js +12 -0
- package/dblist/controllers/insertItem.js +17 -0
- package/dblist/controllers/readItems.js +7 -0
- package/dblist/controllers/updateItem.js +22 -0
- package/dblist/controllers/utils/checkItem.js +9 -0
- package/dblist/index.js +40 -0
- package/index.js +2 -0
- package/package.json +1 -1
- package/server/migrations/crm.sql +2 -0
- package/server/migrations/log.sql +2 -0
- package/table/controllers/search.js +41 -41
- package/table/funcs/getFilterSQL/index.js +1 -1
- package/table/index.js +2 -0
- package/test/api/dblist.test.js +47 -0
- package/test/widget.test.js +5 -5
- package/widget/controllers/utils/historyFormat.js +76 -0
- package/widget/controllers/widget.del.js +0 -2
- package/widget/controllers/widget.get.js +16 -87
- package/widget/controllers/widget.set.js +1 -5
package/Changelog.md
CHANGED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { existsSync } from 'fs';
|
|
2
|
+
import { readFile, writeFile } from 'fs/promises';
|
|
3
|
+
|
|
4
|
+
export default async function deleteItem({ params = {} }) {
|
|
5
|
+
const { id } = params;
|
|
6
|
+
if (!id) return { error: 'not enough params', status: 400 };
|
|
7
|
+
if (!existsSync('dblist.json')) return { data: [] };
|
|
8
|
+
const data = JSON.parse(await readFile('dblist.json') || '[]');
|
|
9
|
+
|
|
10
|
+
await writeFile('dblist.json', JSON.stringify(data.filter((el) => el.id !== id)));
|
|
11
|
+
return { data };
|
|
12
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { randomUUID } from 'crypto';
|
|
2
|
+
import { existsSync } from 'fs';
|
|
3
|
+
import { readFile, writeFile } from 'fs/promises';
|
|
4
|
+
|
|
5
|
+
import checkItem from './utils/checkItem.js';
|
|
6
|
+
|
|
7
|
+
export default async function insertItem({ body = {} }) {
|
|
8
|
+
const check = checkItem(body.data);
|
|
9
|
+
if (check?.error) return check;
|
|
10
|
+
|
|
11
|
+
Object.assign(body.data, { id: randomUUID() });
|
|
12
|
+
const data = existsSync('dblist.json') ? JSON.parse(await readFile('dblist.json') || '[]') : [];
|
|
13
|
+
data.push(body.data);
|
|
14
|
+
|
|
15
|
+
await writeFile('dblist.json', JSON.stringify(data));
|
|
16
|
+
return { data };
|
|
17
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { existsSync } from 'fs';
|
|
2
|
+
import { readFile, writeFile } from 'fs/promises';
|
|
3
|
+
|
|
4
|
+
import checkItem from './utils/checkItem.js';
|
|
5
|
+
|
|
6
|
+
export default async function updateItem({ body = {}, params = {} }) {
|
|
7
|
+
const { id } = params;
|
|
8
|
+
if (!id) return { error: 'not enough params', status: 400 };
|
|
9
|
+
|
|
10
|
+
if (!existsSync('dblist.json')) {
|
|
11
|
+
return { error: 'nothing to update: 1', status: 400 };
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const check = checkItem(body.data);
|
|
15
|
+
if (check?.error) return check;
|
|
16
|
+
|
|
17
|
+
const data = JSON.parse(await readFile('dblist.json') || '[]');
|
|
18
|
+
data.filter((el) => el.id === id)?.forEach((el) => Object.assign(el, body.data));
|
|
19
|
+
|
|
20
|
+
await writeFile('dblist.json', JSON.stringify(data));
|
|
21
|
+
return { data };
|
|
22
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export default function validateItem(item) {
|
|
2
|
+
if (!item || typeof item !== 'object' || Array.isArray(item)) {
|
|
3
|
+
return { error: 'param data is invalid: 1', status: 400 };
|
|
4
|
+
}
|
|
5
|
+
if (!item.options?.database || Object.keys(item).filter((key) => !['key', 'name', 'options'].includes(key) || (typeof item[key] !== 'string' && key !== 'options')).length) {
|
|
6
|
+
return { error: 'param data is invalid: 2', status: 400 };
|
|
7
|
+
}
|
|
8
|
+
return null;
|
|
9
|
+
}
|
package/dblist/index.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import createItem from './controllers/insertItem.js';
|
|
2
|
+
import readItemList from './controllers/readItems.js';
|
|
3
|
+
import updateItem from './controllers/updateItem.js';
|
|
4
|
+
import deleteItem from './controllers/deleteItem.js';
|
|
5
|
+
|
|
6
|
+
export default async function plugin(fastify, config = {}) {
|
|
7
|
+
const prefix = config.prefix || '/api';
|
|
8
|
+
fastify.route({
|
|
9
|
+
method: 'POST',
|
|
10
|
+
url: `${prefix}/list`,
|
|
11
|
+
config: {
|
|
12
|
+
policy: [],
|
|
13
|
+
},
|
|
14
|
+
handler: createItem,
|
|
15
|
+
});
|
|
16
|
+
fastify.route({
|
|
17
|
+
method: 'GET',
|
|
18
|
+
url: `${prefix}/list`,
|
|
19
|
+
config: {
|
|
20
|
+
policy: [],
|
|
21
|
+
},
|
|
22
|
+
handler: readItemList,
|
|
23
|
+
});
|
|
24
|
+
fastify.route({
|
|
25
|
+
method: 'PUT',
|
|
26
|
+
url: `${prefix}/list/:id`,
|
|
27
|
+
config: {
|
|
28
|
+
policy: [],
|
|
29
|
+
},
|
|
30
|
+
handler: updateItem,
|
|
31
|
+
});
|
|
32
|
+
fastify.route({
|
|
33
|
+
method: 'DELETE',
|
|
34
|
+
url: `${prefix}/list/:id`,
|
|
35
|
+
config: {
|
|
36
|
+
policy: [],
|
|
37
|
+
},
|
|
38
|
+
handler: deleteItem,
|
|
39
|
+
});
|
|
40
|
+
}
|
package/index.js
CHANGED
|
@@ -10,6 +10,7 @@ import notificationPlugin from './notification/index.js';
|
|
|
10
10
|
import widgetPlugin from './widget/index.js';
|
|
11
11
|
import crudPlugin from './crud/index.js';
|
|
12
12
|
import policyPlugin from './policy/index.js';
|
|
13
|
+
import dbListPlugin from './dblist/index.js';
|
|
13
14
|
|
|
14
15
|
async function plugin(fastify, opt) {
|
|
15
16
|
// console.log(opt);
|
|
@@ -31,6 +32,7 @@ async function plugin(fastify, opt) {
|
|
|
31
32
|
crudPlugin(fastify, opt);
|
|
32
33
|
notificationPlugin(fastify, opt);
|
|
33
34
|
widgetPlugin(fastify, opt);
|
|
35
|
+
dbListPlugin(fastify, opt);
|
|
34
36
|
}
|
|
35
37
|
export default fp(plugin);
|
|
36
38
|
// export { rclient };
|
package/package.json
CHANGED
|
@@ -24,10 +24,12 @@ ALTER TABLE crm.file ADD COLUMN IF NOT EXISTS file_id text NOT NULL DEFAULT admi
|
|
|
24
24
|
ALTER TABLE crm.file ADD COLUMN IF NOT EXISTS upload_name text;
|
|
25
25
|
ALTER TABLE crm.file ADD COLUMN IF NOT EXISTS object_id text;
|
|
26
26
|
ALTER TABLE crm.file ADD COLUMN IF NOT EXISTS file_type text;
|
|
27
|
+
ALTER TABLE crm.file ADD COLUMN IF NOT EXISTS file_status numeric;
|
|
27
28
|
ALTER TABLE crm.file ADD COLUMN IF NOT EXISTS doc_type text;
|
|
28
29
|
ALTER TABLE crm.file ADD COLUMN IF NOT EXISTS title text;
|
|
29
30
|
ALTER TABLE crm.file ADD COLUMN IF NOT EXISTS size numeric;
|
|
30
31
|
ALTER TABLE crm.file ADD COLUMN IF NOT EXISTS ext text;
|
|
32
|
+
ALTER TABLE crm.file ADD COLUMN IF NOT EXISTS tags text[];
|
|
31
33
|
ALTER TABLE crm.file ADD COLUMN IF NOT EXISTS file_path text;
|
|
32
34
|
ALTER TABLE crm.file ADD COLUMN IF NOT EXISTS ismain boolean default false;
|
|
33
35
|
ALTER TABLE crm.file ADD COLUMN IF NOT EXISTS isverified boolean default false;
|
|
@@ -3,6 +3,8 @@ ALTER TABLE log.table_change DROP CONSTRAINT IF EXISTS log_table_change_pkey;
|
|
|
3
3
|
ALTER TABLE log.table_change ADD COLUMN IF NOT EXISTS table_change_id text NOT NULL DEFAULT admin.next_id();
|
|
4
4
|
|
|
5
5
|
ALTER TABLE log.table_change ADD COLUMN IF NOT EXISTS table_name text;
|
|
6
|
+
ALTER TABLE log.table_change ADD COLUMN IF NOT EXISTS object_id text;
|
|
7
|
+
ALTER TABLE log.table_change ADD COLUMN IF NOT EXISTS change_type text;
|
|
6
8
|
ALTER TABLE log.table_change ADD COLUMN IF NOT EXISTS change_key text;
|
|
7
9
|
ALTER TABLE log.table_change ADD COLUMN IF NOT EXISTS change_date date;
|
|
8
10
|
ALTER TABLE log.table_change ADD COLUMN IF NOT EXISTS json_old json;
|
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
import getTemplate from './utils/getTemplate.js';
|
|
2
|
-
import getMeta from '../../pg/funcs/getMeta.js';
|
|
3
|
-
import metaFormat from '../funcs/metaFormat/index.js';
|
|
4
|
-
|
|
5
|
-
const maxLimit = 100;
|
|
6
|
-
|
|
7
|
-
export default async function data({
|
|
8
|
-
pg, query = {},
|
|
9
|
-
}) {
|
|
10
|
-
const time = Date.now();
|
|
11
|
-
|
|
12
|
-
const loadTable = await getTemplate('table', query.table);
|
|
13
|
-
|
|
14
|
-
if (!loadTable) { return { message: 'not found', status: 404 }; }
|
|
15
|
-
|
|
16
|
-
const { table, columns, meta } = loadTable;
|
|
17
|
-
const { pk } = await getMeta(table);
|
|
18
|
-
|
|
19
|
-
const cols = columns.map((el) => el.name || el).join(',');
|
|
20
|
-
const [orderColumn, orderDir] = (query.order || loadTable.order || '').split('-');
|
|
21
|
-
const order = cols.includes(orderColumn) && orderColumn?.length ? `order by ${orderColumn} ${query.desc || orderDir === 'desc' ? 'desc' : ''}` : '';
|
|
22
|
-
|
|
23
|
-
const limit = Math.min(maxLimit, +(query.limit || 10));
|
|
24
|
-
const offset = query.page && query.page > 0 ? ` offset ${(query.page - 1) * limit}` : '';
|
|
25
|
-
|
|
26
|
-
const search = meta?.search && query.key ? `(${meta?.search.concat(meta?.title ? `,${meta?.title}` : '').split(',').map(el => `${el} ilike '%${query.key}%'`).join(' or ')})` : null;
|
|
27
|
-
|
|
28
|
-
const where = [loadTable.query, search].filter((el) => el);
|
|
29
|
-
const q = `select ${pk ? `"${pk}" as id,` : ''} * from ${table} t where ${where.join(' and ') || 'true'} ${order} ${offset} limit ${limit}`;
|
|
30
|
-
|
|
31
|
-
if (query.sql === '1') return q;
|
|
32
|
-
|
|
33
|
-
const { rows } = await pg.query(q);
|
|
34
|
-
|
|
35
|
-
const total = await pg.queryCache(`select count(*) from ${table} t where ${where.join(' and ') || 'true'}`).then((el) => el?.rows[0]?.count);
|
|
36
|
-
|
|
37
|
-
await metaFormat({ rows, table: query.table });
|
|
38
|
-
return {
|
|
39
|
-
time: Date.now() - time, total, count: rows.length, rows,
|
|
40
|
-
};
|
|
41
|
-
}
|
|
1
|
+
import getTemplate from './utils/getTemplate.js';
|
|
2
|
+
import getMeta from '../../pg/funcs/getMeta.js';
|
|
3
|
+
import metaFormat from '../funcs/metaFormat/index.js';
|
|
4
|
+
|
|
5
|
+
const maxLimit = 100;
|
|
6
|
+
|
|
7
|
+
export default async function data({
|
|
8
|
+
pg, query = {},
|
|
9
|
+
}) {
|
|
10
|
+
const time = Date.now();
|
|
11
|
+
|
|
12
|
+
const loadTable = await getTemplate('table', query.table);
|
|
13
|
+
|
|
14
|
+
if (!loadTable) { return { message: 'not found', status: 404 }; }
|
|
15
|
+
|
|
16
|
+
const { table, columns, meta } = loadTable;
|
|
17
|
+
const { pk } = await getMeta(table);
|
|
18
|
+
|
|
19
|
+
const cols = columns.map((el) => el.name || el).join(',');
|
|
20
|
+
const [orderColumn, orderDir] = (query.order || loadTable.order || '').split('-');
|
|
21
|
+
const order = cols.includes(orderColumn) && orderColumn?.length ? `order by ${orderColumn} ${query.desc || orderDir === 'desc' ? 'desc' : ''}` : '';
|
|
22
|
+
|
|
23
|
+
const limit = Math.min(maxLimit, +(query.limit || 10));
|
|
24
|
+
const offset = query.page && query.page > 0 ? ` offset ${(query.page - 1) * limit}` : '';
|
|
25
|
+
|
|
26
|
+
const search = meta?.search && query.key ? `(${meta?.search.concat(meta?.title ? `,${meta?.title}` : '').split(',').map(el => `${el} ilike '%${query.key}%'`).join(' or ')})` : null;
|
|
27
|
+
|
|
28
|
+
const where = [loadTable.query, search].filter((el) => el);
|
|
29
|
+
const q = `select ${pk ? `"${pk}" as id,` : ''} * from ${table} t where ${where.join(' and ') || 'true'} ${order} ${offset} limit ${limit}`;
|
|
30
|
+
|
|
31
|
+
if (query.sql === '1') return q;
|
|
32
|
+
|
|
33
|
+
const { rows } = await pg.query(q);
|
|
34
|
+
|
|
35
|
+
const total = await pg.queryCache(`select count(*) from ${table} t where ${where.join(' and ') || 'true'}`).then((el) => el?.rows[0]?.count);
|
|
36
|
+
|
|
37
|
+
await metaFormat({ rows, table: query.table });
|
|
38
|
+
return {
|
|
39
|
+
time: Date.now() - time, total, count: rows.length, rows,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
@@ -42,7 +42,7 @@ async function getFilterSQL({
|
|
|
42
42
|
filter,
|
|
43
43
|
tableSQL,
|
|
44
44
|
fields,
|
|
45
|
-
filterList: filterList || (body?.filter_list || []).concat(body
|
|
45
|
+
filterList: filterList || (body?.filter_list || []).concat(body?.filterInline || []).concat(body?.filterCustom || []).concat(body?.filterState || []).concat(body?.filterList || []),
|
|
46
46
|
pg,
|
|
47
47
|
config,
|
|
48
48
|
});
|
package/table/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import search from './controllers/search.js';
|
|
|
4
4
|
import filter from './controllers/filter.js';
|
|
5
5
|
import form from './controllers/form.js';
|
|
6
6
|
import metaFormat from './funcs/metaFormat/index.js';
|
|
7
|
+
import getFilterSQL from './funcs/getFilterSQL/index.js';
|
|
7
8
|
|
|
8
9
|
const tableSchema = {
|
|
9
10
|
querystring: {
|
|
@@ -27,6 +28,7 @@ const searchTableSchema = {
|
|
|
27
28
|
async function plugin(fastify, config = {}) {
|
|
28
29
|
const prefix = config.prefix || '/api';
|
|
29
30
|
fastify.decorate('metaFormat', metaFormat);
|
|
31
|
+
fastify.decorate('getFilterSQL', getFilterSQL);
|
|
30
32
|
|
|
31
33
|
fastify.get(`${prefix}/suggest/:data`, {}, suggest);
|
|
32
34
|
fastify.get(`${prefix}/data/:table/:id?`, { schema: tableSchema }, data); // vs.crm.data.api с node
|
|
@@ -0,0 +1,47 @@
|
|
|
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 prefix = config.prefix || '/api';
|
|
8
|
+
|
|
9
|
+
test('api dblist', async (t) => {
|
|
10
|
+
const app = await build(t);
|
|
11
|
+
await t.test('GET /list', async () => {
|
|
12
|
+
const res = await app.inject({
|
|
13
|
+
method: 'GET',
|
|
14
|
+
url: `${prefix}/list`,
|
|
15
|
+
});
|
|
16
|
+
const rep = JSON.parse(res?.body);
|
|
17
|
+
assert.ok(rep.data);
|
|
18
|
+
});
|
|
19
|
+
let id;
|
|
20
|
+
await t.test('POST /list', async () => {
|
|
21
|
+
const res = await app.inject({
|
|
22
|
+
method: 'POST',
|
|
23
|
+
url: `${prefix}/list`,
|
|
24
|
+
body: { data: { key: 'testDB', name: 'testTitle', options: { database: 'mbk_kr_prod' } } },
|
|
25
|
+
});
|
|
26
|
+
const rep = JSON.parse(res?.body);
|
|
27
|
+
id = rep.data?.find((el) => el.key === 'testDB')?.id;
|
|
28
|
+
assert.ok(id);
|
|
29
|
+
});
|
|
30
|
+
await t.test('PUT /list/:id', async () => {
|
|
31
|
+
const res = await app.inject({
|
|
32
|
+
method: 'PUT',
|
|
33
|
+
url: `${prefix}/list/${id}`,
|
|
34
|
+
body: { data: { key: 'testDB1', name: 'testTitle1', options: { host: '192.168.3.160', database: 'mbk_kr_prod', port: 5434 } } },
|
|
35
|
+
});
|
|
36
|
+
const rep = JSON.parse(res?.body);
|
|
37
|
+
assert.ok(rep.data);
|
|
38
|
+
});
|
|
39
|
+
await t.test('DELETE /list/:id', async () => {
|
|
40
|
+
const res = await app.inject({
|
|
41
|
+
method: 'DELETE',
|
|
42
|
+
url: `${prefix}/list/${id}`,
|
|
43
|
+
});
|
|
44
|
+
const rep = JSON.parse(res?.body);
|
|
45
|
+
assert.ok(rep.data);
|
|
46
|
+
});
|
|
47
|
+
});
|
package/test/widget.test.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { test } from 'node:test';
|
|
2
2
|
import assert from 'node:assert';
|
|
3
3
|
|
|
4
|
-
import build from '
|
|
4
|
+
import build from '../helper.js';
|
|
5
5
|
import config from '../config.js';
|
|
6
6
|
|
|
7
7
|
const session = { passport: { user: { uid: config.testUser?.uid || '1' } } };
|
|
8
8
|
|
|
9
|
-
import widgetGet from '
|
|
10
|
-
import widgetSet from '
|
|
11
|
-
import widgetDel from '
|
|
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
12
|
|
|
13
|
-
import pgClients from '
|
|
13
|
+
import pgClients from '../pg/pgClients.js';
|
|
14
14
|
|
|
15
15
|
test('api && funcs notification', async (t) => {
|
|
16
16
|
const app = await build(t);
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { readdir } from 'fs/promises';
|
|
2
|
+
import { existsSync, readFileSync } from 'fs';
|
|
3
|
+
|
|
4
|
+
// import getTemplate from '../../../table/controllers/utils/getTemplate.js';
|
|
5
|
+
import getSelect from '../../../table/controllers/utils/getSelect.js';
|
|
6
|
+
|
|
7
|
+
const dbData = {};
|
|
8
|
+
|
|
9
|
+
// from config??
|
|
10
|
+
const allTemplates = { table: {} };
|
|
11
|
+
|
|
12
|
+
const historyQ = `select nspname||'.'||relname as table_name, json_agg(json_build_object('name',attname, 'title',coalesce(col_description(attrelid, attnum),attname))) as columns
|
|
13
|
+
from pg_attribute a
|
|
14
|
+
left join pg_catalog.pg_attrdef d ON (a.attrelid, a.attnum) = (d.adrelid, d.adnum)
|
|
15
|
+
JOIN pg_class AS i
|
|
16
|
+
ON i.oid = a.attrelid
|
|
17
|
+
JOIN pg_namespace AS NS ON i.relnamespace = NS.OID
|
|
18
|
+
where a.attnum > 0
|
|
19
|
+
and not a.attisdropped
|
|
20
|
+
group by nspname||'.'||relname`;
|
|
21
|
+
|
|
22
|
+
export default async function historyFormat(rows, table, pg) {
|
|
23
|
+
if (!rows?.[0]?.changes) return rows; // old structure
|
|
24
|
+
// on startup
|
|
25
|
+
if (!allTemplates.table.length) {
|
|
26
|
+
const templateDir = './server/templates/table';
|
|
27
|
+
const templates = existsSync(templateDir) ? await readdir(templateDir) : [];
|
|
28
|
+
templates.forEach((template) => {
|
|
29
|
+
const body = JSON.parse(readFileSync(`${templateDir}/${template}`) || '{}');
|
|
30
|
+
Object.assign(allTemplates.table, { [template]: body });
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const progrid = Object.keys(allTemplates.table).find((key) => key.replace('.json', '') === table);
|
|
35
|
+
if (!progrid) return rows;
|
|
36
|
+
// const body = await getTemplate('table', progrid);
|
|
37
|
+
const body = allTemplates.table[progrid];
|
|
38
|
+
const tableName = body?.table || table;
|
|
39
|
+
if (!tableName) return rows;
|
|
40
|
+
|
|
41
|
+
// get DB column description
|
|
42
|
+
if (!dbData?.[body.table]?.length) {
|
|
43
|
+
const { rows: rows1 } = await pg.query(historyQ);
|
|
44
|
+
rows1.forEach((row) => {
|
|
45
|
+
dbData[row.table_name] = row.columns;
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// rewrite!!!
|
|
50
|
+
await Promise.all(rows?.map(async (op) => {
|
|
51
|
+
op.changes?.map(async (el) => {
|
|
52
|
+
const col = body.colModel.filter((col1) => col1.name === el.attr)[0] || dbData[body?.table]?.find((col1) => col1.name === el.attr);
|
|
53
|
+
if (el.attr === 'geom') {
|
|
54
|
+
el.title = 'Геометрія';
|
|
55
|
+
}
|
|
56
|
+
el.title = col?.ua || col?.title || el.attr;
|
|
57
|
+
if (!col) return;
|
|
58
|
+
el.type = col.type;
|
|
59
|
+
el.format = col.format;
|
|
60
|
+
const select = col.data || col.option || col.select;
|
|
61
|
+
|
|
62
|
+
// getSelect not equals to node
|
|
63
|
+
if (select && false) {
|
|
64
|
+
el.select = select;
|
|
65
|
+
const cls = await getSelect(select, {
|
|
66
|
+
val: [el.old, el.new],
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
el.oldf = cls[0] || el.old;
|
|
70
|
+
el.newf = cls[1] || el.new;
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}));
|
|
74
|
+
|
|
75
|
+
return rows;
|
|
76
|
+
}
|
|
@@ -29,8 +29,6 @@ export default async function widgetDel({
|
|
|
29
29
|
const sql = {
|
|
30
30
|
comment: 'delete from crm.comment where object_id=$1 and uid=$2 and comment_id=$3',
|
|
31
31
|
checklist: 'delete from crm.checklist where object_id=$1 and uid=$2 and checklist_id=$3 ',
|
|
32
|
-
link: 'delete from crm.link where object_id=$1 and uid=$2 and link_id=$3 ',
|
|
33
|
-
time: 'delete from crm.elapsed_time where object_id=$1 and uid=$2 and elapsed_time_id=$3 ',
|
|
34
32
|
};
|
|
35
33
|
try {
|
|
36
34
|
const { rows, rowCount } = await pg.query(sql[type], [objectid, user.uid, id]);
|
|
@@ -1,61 +1,6 @@
|
|
|
1
|
-
import getTemplate from '../../table/controllers/utils/getTemplate.js';
|
|
2
|
-
import getSelect from '../../table/controllers/utils/getSelect.js';
|
|
3
1
|
import getToken from '../../crud/funcs/getToken.js';
|
|
4
2
|
import getMeta from '../../pg/funcs/getMeta.js';
|
|
5
|
-
|
|
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
|
-
}
|
|
3
|
+
import historyFormat from './utils/historyFormat.js';
|
|
59
4
|
|
|
60
5
|
/**
|
|
61
6
|
* Дістає CRM для widget
|
|
@@ -73,36 +18,24 @@ export default async function widgetGet({
|
|
|
73
18
|
|
|
74
19
|
const objectid = param ? JSON.parse(param)?.id : params.objectid;
|
|
75
20
|
|
|
76
|
-
if (!['comment', 'history', 'file', 'checklist'
|
|
21
|
+
if (!['comment', 'history', 'file', 'checklist'].includes(params.type)) return { error: 'param type not valid', status: 400 };
|
|
77
22
|
if (!objectid) return { error: 'id required', status: 400 };
|
|
78
23
|
|
|
79
24
|
const sql = {
|
|
80
25
|
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
|
|
26
|
+
from crm.comment c left join admin.users u on u.uid=c.uid where object_id=$1 order by cdate desc`,
|
|
82
27
|
|
|
83
|
-
|
|
84
|
-
|
|
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`,
|
|
28
|
+
history: `SELECT object_id, table_name, change_key, change_date, json_old, json_new, date_old,
|
|
29
|
+
date_new, number_old, number_new, bool_old, bool_new, text_old,
|
|
30
|
+
text_new, uid, cdate FROM log.table_change where object_id=$1 order by cdate desc, change_key limit 100`,
|
|
92
31
|
|
|
93
32
|
checklist: `SELECT checklist_id, title, is_done, done_date, c.uid, c.cdate, coalesce(user_name,' ')||' '||coalesce(sur_name,'') as username,
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
link: `SELECT link_id, link, title, meta FROM crm.link
|
|
97
|
-
where object_id=$1 order by cdate desc`,
|
|
33
|
+
avatar FROM crm.checklist c left join admin.users u on u.uid=c.uid where object_id=$1 order by cdate desc`,
|
|
98
34
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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`,
|
|
35
|
+
file: `SELECT file_id, file_path, uploaded_name, ext, size, c.uid, c.cdate, file_type, c.ismain,
|
|
36
|
+
coalesce(user_name,' ')||' '||coalesce(sur_name,'') as username, isverified,
|
|
37
|
+
avatar, c.uid as author, file_status FROM crm.file c left join admin.users u on u.uid=c.uid
|
|
38
|
+
where object_id=$1 and file_status<>3 order by cdate desc`,
|
|
106
39
|
|
|
107
40
|
};
|
|
108
41
|
try {
|
|
@@ -112,26 +45,22 @@ export default async function widgetGet({
|
|
|
112
45
|
time.push(Date.now());
|
|
113
46
|
|
|
114
47
|
/* Object info */
|
|
115
|
-
const { tableName } = await pg.one(
|
|
116
|
-
where pk_id = $1 /*and _type ='INSERT'*/ limit 1`, [objectid]);
|
|
48
|
+
const { tableName } = await pg.one('select table_name as "tableName" from log.table_change where object_id=$1 limit 1', [objectid]);
|
|
117
49
|
const { pk } = await getMeta({ table: tableName });
|
|
118
|
-
|
|
119
|
-
from ${tableName} a left join admin.users b on a.uid=b.uid where a.${pk}=$1 limit 1`;
|
|
50
|
+
|
|
51
|
+
const q = `select coalesce(b.user_name,'')||coalesce(' '||b.sur_name,'') as author, a.cdate, a.editor_date from ${tableName} a left join admin.users b on a.uid=b.uid where a.${pk}=$1 limit 1`;
|
|
120
52
|
const data = pk ? await pg.one(q, [objectid]) : {};
|
|
53
|
+
|
|
121
54
|
if (query.debug && user?.user_type === 'admin') {
|
|
122
55
|
return {
|
|
123
56
|
sql, type: params.type, q, id: objectid, data,
|
|
124
57
|
};
|
|
125
58
|
}
|
|
126
59
|
|
|
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
60
|
time.push(Date.now());
|
|
131
61
|
return {
|
|
132
|
-
progrid,
|
|
133
62
|
time: { data: time[1] - time[0], format: time[2] - time[1] },
|
|
134
|
-
rows: params.type === 'history' ? await historyFormat(rows,
|
|
63
|
+
rows: params.type === 'history' ? await historyFormat(rows, tableName, pg) : rows,
|
|
135
64
|
user: { uid: user?.uid, name: user?.user_name },
|
|
136
65
|
data: { author: data?.author, cdate: data?.cdate, edate: data?.editor_date },
|
|
137
66
|
objectid: params.objectid,
|
|
@@ -3,14 +3,10 @@ import getMeta from '../../pg/funcs/getMeta.js';
|
|
|
3
3
|
|
|
4
4
|
const tableList = {
|
|
5
5
|
comment: 'crm.comment',
|
|
6
|
-
link: 'crm.link',
|
|
7
|
-
time: 'crm.elapsed_time',
|
|
8
6
|
checklist: 'crm.checklist',
|
|
9
7
|
};
|
|
10
8
|
const pkList = {
|
|
11
9
|
comment: 'comment_id',
|
|
12
|
-
link: 'link_id',
|
|
13
|
-
time: 'elapsed_time_id',
|
|
14
10
|
checklist: 'checklist_id',
|
|
15
11
|
};
|
|
16
12
|
|
|
@@ -19,7 +15,7 @@ export default async function widgetSet({
|
|
|
19
15
|
}) {
|
|
20
16
|
const { user = {} } = session.passport || {};
|
|
21
17
|
const { type, id, objectid } = params;
|
|
22
|
-
if (!['comment', 'checklist'
|
|
18
|
+
if (!['comment', 'checklist'].includes(type)) return { error: 'param type not valid', status: 400 };
|
|
23
19
|
if (!objectid) return { error: 'id required', status: 400 };
|
|
24
20
|
|
|
25
21
|
const table = tableList[type];
|