@opengis/fastify-table 2.0.148 → 2.0.150
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/dist/config.d.ts.map +1 -1
- package/dist/config.js +7 -0
- package/dist/server/plugins/crud/funcs/utils/logChanges.d.ts +2 -0
- package/dist/server/plugins/crud/funcs/utils/logChanges.d.ts.map +1 -1
- package/dist/server/plugins/crud/funcs/utils/logChanges.js +84 -33
- package/dist/server/routes/widget/controllers/widget.get.d.ts +1 -1
- package/dist/server/routes/widget/controllers/widget.get.d.ts.map +1 -1
- package/dist/server/routes/widget/controllers/widget.get.js +27 -33
- package/package.json +1 -1
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../config.ts"],"names":[],"mappings":"AAWA,QAAA,MAAM,MAAM,KAA8D,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../config.ts"],"names":[],"mappings":"AAWA,QAAA,MAAM,MAAM,KAA8D,CAAC;AAgD3E,eAAe,MAAM,CAAC"}
|
package/dist/config.js
CHANGED
|
@@ -15,6 +15,13 @@ Object.assign(config, {
|
|
|
15
15
|
if (existsSync(`.env.local`)) {
|
|
16
16
|
dotenv.config({ path: `.env.local` }); // ! load .env.local
|
|
17
17
|
}
|
|
18
|
+
// example: bun server kamianske
|
|
19
|
+
if (process.cwd().split("\\").pop() &&
|
|
20
|
+
process.cwd().split("\\").pop() === "fastify-table" &&
|
|
21
|
+
process.argv[2] &&
|
|
22
|
+
existsSync(`.env.${process.argv[2]}`)) {
|
|
23
|
+
dotenv.config({ path: `.env.${process.argv[2]}` }); // ! for debug only
|
|
24
|
+
}
|
|
18
25
|
if (process.env?.NODE_ENV && existsSync(`.env.${process.env.NODE_ENV}`)) {
|
|
19
26
|
dotenv.config({ path: `.env.${process.env.NODE_ENV}` }); // ! load .env.{{production}} etc.
|
|
20
27
|
}
|
|
@@ -16,6 +16,7 @@ export default function logChanges({ pg, table: table1, tokenData, referer, id,
|
|
|
16
16
|
change_type: string;
|
|
17
17
|
old: any;
|
|
18
18
|
new: any;
|
|
19
|
+
titles: Record<string, string>;
|
|
19
20
|
error?: undefined;
|
|
20
21
|
} | {
|
|
21
22
|
error: any;
|
|
@@ -26,5 +27,6 @@ export default function logChanges({ pg, table: table1, tokenData, referer, id,
|
|
|
26
27
|
change_id?: undefined;
|
|
27
28
|
old?: undefined;
|
|
28
29
|
new?: undefined;
|
|
30
|
+
titles?: undefined;
|
|
29
31
|
} | null>;
|
|
30
32
|
//# sourceMappingURL=logChanges.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logChanges.d.ts","sourceRoot":"","sources":["../../../../../../server/plugins/crud/funcs/utils/logChanges.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"logChanges.d.ts","sourceRoot":"","sources":["../../../../../../server/plugins/crud/funcs/utils/logChanges.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,2BAA2B,CAAC;AA8C5D,wBAA8B,UAAU,CAAC,EACvC,EAAE,EACF,KAAK,EAAE,MAAM,EACb,SAAS,EACT,OAAO,EACP,EAAE,EACF,IAAI,EACJ,GAAO,EACP,IAAI,GACL,EAAE;IACD,EAAE,EAAE,UAAU,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;CACd;;;;;;;;;;;;;;;;;;;;UA8MA"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import getTemplate from "../../../table/funcs/getTemplate.js";
|
|
3
3
|
import metaFormat from "../../../table/funcs/metaFormat/index.js";
|
|
4
|
+
import getMeta from "../../../pg/funcs/getMeta.js";
|
|
4
5
|
const defaultTitles = {
|
|
5
6
|
editor_date: "Дата оновлення",
|
|
6
7
|
editor_id: "Редактор",
|
|
@@ -14,15 +15,26 @@ const defaultTitles = {
|
|
|
14
15
|
size: "Розмір файлу",
|
|
15
16
|
ext: "Розширення файлу",
|
|
16
17
|
};
|
|
17
|
-
|
|
18
|
+
// skip log of system columns changes made by CRUD functions - log only changes of data
|
|
19
|
+
const systemColumns = [
|
|
20
|
+
"cdate",
|
|
21
|
+
"editor_date",
|
|
22
|
+
"created_at",
|
|
23
|
+
"updated_at",
|
|
24
|
+
"editor_id",
|
|
25
|
+
"uid",
|
|
26
|
+
"updated_by",
|
|
27
|
+
"created_by",
|
|
28
|
+
];
|
|
29
|
+
function getValue(val, tableName, columnTypes) {
|
|
30
|
+
if (typeof val === "boolean")
|
|
31
|
+
return val;
|
|
18
32
|
if (!val)
|
|
19
33
|
return null;
|
|
20
34
|
if (["crm.files"].includes(tableName)) {
|
|
21
35
|
return typeof val === "object" ? JSON.stringify(val) : val;
|
|
22
36
|
}
|
|
23
|
-
return typeof val === "object"
|
|
24
|
-
? JSON.stringify(val)?.substring?.(0, 30)
|
|
25
|
-
: val?.toString?.()?.substring?.(0, 30);
|
|
37
|
+
return typeof val === "object" ? null : val?.toString?.()?.substring?.(0, 30);
|
|
26
38
|
}
|
|
27
39
|
// extract titles and cls from form schema
|
|
28
40
|
// alt: extract table template from referer -> form
|
|
@@ -49,10 +61,11 @@ export default async function logChanges({ pg, table: table1, tokenData, referer
|
|
|
49
61
|
.query(`insert into log.table_changes(change_date,change_type,change_user_id,entity_type,entity_id)
|
|
50
62
|
values(CURRENT_DATE, $1, $2, $3, $4) returning change_id`, [type, uid, table, id])
|
|
51
63
|
.then((el) => el.rows?.[0] || {});
|
|
52
|
-
const q = `select json_object_agg(entity_key, value_hash) from (
|
|
64
|
+
const q = `select json_object_agg(entity_key, json_build_object('hash',value_hash,'value',value_new)) from (
|
|
53
65
|
select
|
|
54
66
|
entity_key,
|
|
55
67
|
value_hash,
|
|
68
|
+
value_new,
|
|
56
69
|
( rank() over (partition by entity_key order by cdate desc) = 1 ) as is_latest
|
|
57
70
|
from log.table_changes_data
|
|
58
71
|
|
|
@@ -74,33 +87,70 @@ export default async function logChanges({ pg, table: table1, tokenData, referer
|
|
|
74
87
|
const body = await getTemplate("form", tokenData?.form);
|
|
75
88
|
const schema = body?.schema || body || {};
|
|
76
89
|
const titles = Object.keys(schema).reduce((acc, curr) => Object.assign(acc, { [curr]: schema[curr].title || schema[curr].ua }), {});
|
|
90
|
+
Object.assign(titles, defaultTitles);
|
|
77
91
|
const cls = Object.keys(schema)
|
|
78
92
|
.filter((el) => schema[el]?.data)
|
|
79
93
|
.reduce((acc, curr) => Object.assign(acc, { [curr]: schema[curr].data }), {});
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
+
// const original = JSON.parse(JSON.stringify(data));
|
|
95
|
+
const row = await metaFormat({
|
|
96
|
+
rows: [data].filter(Boolean),
|
|
97
|
+
cls,
|
|
98
|
+
sufix: false,
|
|
99
|
+
reassign: false,
|
|
100
|
+
}, pg).then((el) => el[0]);
|
|
101
|
+
const newObj1 = {};
|
|
102
|
+
const meta = await getMeta({ pg, table });
|
|
103
|
+
const columnTypes = (meta?.columns || []).reduce((acc, curr) => ({
|
|
104
|
+
...acc,
|
|
105
|
+
[curr.name]: pg?.pgType?.[curr.dataTypeID],
|
|
106
|
+
}), {});
|
|
107
|
+
if (type !== "DELETE") {
|
|
108
|
+
Object.keys(row || {})
|
|
109
|
+
.filter((key) => !systemColumns.includes(key))
|
|
110
|
+
.reduce((acc, curr) => {
|
|
111
|
+
Object.assign(newObj1, {
|
|
112
|
+
[titles[curr] || curr]: columnTypes[curr] === "geometry"
|
|
113
|
+
? {}
|
|
114
|
+
: {
|
|
115
|
+
value: getValue(row[curr], table, columnTypes),
|
|
116
|
+
hash: typeof row[curr] === "boolean" || row[curr]
|
|
117
|
+
? createHash("md5")
|
|
118
|
+
.update(JSON.stringify(row[curr]))
|
|
119
|
+
.digest("hex")
|
|
120
|
+
: null,
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
return acc;
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
const newGeoms = await Promise.all(Object.keys(newObj1)
|
|
127
|
+
.filter((key) => row[key] && columnTypes[key] === "geometry")
|
|
128
|
+
.map(async (key) => pg
|
|
129
|
+
.query(typeof row[key] === "string" // binary geometry as string via update?
|
|
130
|
+
? "select st_asgeojson(st_pointonsurface($1))::json"
|
|
131
|
+
: "select st_asgeojson(st_pointonsurface(st_geomfromgeojson($1)))::json", [row[key]])
|
|
132
|
+
.then((el) => ({ key, geometry: el.rows[0].st_asgeojson })))).then((r) => r.reduce((acc, curr) => {
|
|
133
|
+
const value = curr.geometry.coordinates.join(",");
|
|
134
|
+
const hash = createHash("md5")
|
|
135
|
+
.update(JSON.stringify(value))
|
|
136
|
+
.digest("hex");
|
|
137
|
+
newObj1[curr.key] = { value, hash };
|
|
138
|
+
return { ...acc, [curr.key]: { value, hash } };
|
|
139
|
+
}, {}));
|
|
140
|
+
const changesData = Object.keys(newObj1 || {})
|
|
141
|
+
.filter((key) => typeof newObj1?.[key] === "boolean" || newObj1?.[key])
|
|
142
|
+
.filter((key) => old[key] ? old[key].hash !== newObj1[key]?.hash : newObj1[key]?.hash)
|
|
143
|
+
.map((key) => ({
|
|
94
144
|
change_id: changeId,
|
|
95
|
-
entity_key:
|
|
96
|
-
value_old:
|
|
97
|
-
value_new:
|
|
98
|
-
value_hash:
|
|
99
|
-
? createHash("md5").update(JSON.stringify(newObj?.[el])).digest("hex")
|
|
100
|
-
: null,
|
|
145
|
+
entity_key: key,
|
|
146
|
+
value_old: old?.[key]?.value,
|
|
147
|
+
value_new: newObj1?.[key]?.value,
|
|
148
|
+
value_hash: newObj1?.[key]?.hash,
|
|
101
149
|
uid,
|
|
102
|
-
}))
|
|
103
|
-
|
|
150
|
+
}));
|
|
151
|
+
if (process.env.NODE_ENV === "test") {
|
|
152
|
+
console.log("changesData", changesData);
|
|
153
|
+
}
|
|
104
154
|
const res = await Promise.all(changesData.map(async (el) => {
|
|
105
155
|
const insertQuery = `insert into log.table_changes_data (${Object.entries(el)
|
|
106
156
|
?.map((key) => `"${key[0]}"`)
|
|
@@ -108,18 +158,18 @@ export default async function logChanges({ pg, table: table1, tokenData, referer
|
|
|
108
158
|
values (${Object.entries(el)
|
|
109
159
|
?.map((key, i) => `$${i + 1}`)
|
|
110
160
|
.join(",")}) returning *`;
|
|
111
|
-
const
|
|
161
|
+
const row1 = await pg
|
|
162
|
+
.query(insertQuery, [
|
|
112
163
|
...Object.entries(el).map((el1) => el1[1] &&
|
|
113
164
|
typeof el1[1] === "object" &&
|
|
114
165
|
(!Array.isArray(el1[1]) || typeof el1[1]?.[0] === "object")
|
|
115
166
|
? JSON.stringify(el1[1])
|
|
116
167
|
: el1[1]),
|
|
117
|
-
])
|
|
118
|
-
|
|
168
|
+
])
|
|
169
|
+
.then((el) => el.rows?.[0] || {});
|
|
170
|
+
return row1;
|
|
119
171
|
}));
|
|
120
|
-
const newData =
|
|
121
|
-
? {}
|
|
122
|
-
: (Array.isArray(res) ? res : [res]).reduce((acc, curr) => Object.assign(acc, { [curr.entity_key]: curr.value_new }), {});
|
|
172
|
+
const newData = (Array.isArray(res) ? res : [res]).reduce((acc, curr) => Object.assign(acc, { [curr.entity_key]: curr.value_new }), {});
|
|
123
173
|
// console.log('logChanges OK', type);
|
|
124
174
|
return {
|
|
125
175
|
change_id: changeId,
|
|
@@ -129,6 +179,7 @@ export default async function logChanges({ pg, table: table1, tokenData, referer
|
|
|
129
179
|
change_type: type,
|
|
130
180
|
old,
|
|
131
181
|
new: newData,
|
|
182
|
+
titles,
|
|
132
183
|
};
|
|
133
184
|
}
|
|
134
185
|
catch (err) {
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
* Дістає CRM для widget
|
|
3
3
|
*
|
|
4
4
|
*/
|
|
5
|
-
export default function widgetGet({ pg, user, params, query
|
|
5
|
+
export default function widgetGet({ pg, user, params, query }: any, reply: any): Promise<any>;
|
|
6
6
|
//# sourceMappingURL=widget.get.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"widget.get.d.ts","sourceRoot":"","sources":["../../../../../server/routes/widget/controllers/widget.get.ts"],"names":[],"mappings":"AAyBA;;;GAGG;AAEH,wBAA8B,SAAS,CACrC,EAAE,EAAqB,EAAE,IAAS,EAAE,MAAW,EAAE,KAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"widget.get.d.ts","sourceRoot":"","sources":["../../../../../server/routes/widget/controllers/widget.get.ts"],"names":[],"mappings":"AAyBA;;;GAGG;AAEH,wBAA8B,SAAS,CACrC,EAAE,EAAqB,EAAE,IAAS,EAAE,MAAW,EAAE,KAAU,EAAE,EAAE,GAAG,EAClE,KAAK,EAAE,GAAG,gBA+KX"}
|
|
@@ -23,7 +23,8 @@ const pkList = {
|
|
|
23
23
|
* Дістає CRM для widget
|
|
24
24
|
*
|
|
25
25
|
*/
|
|
26
|
-
export default async function widgetGet({ pg = pgClients.client, user = {}, params = {}, query = {}
|
|
26
|
+
export default async function widgetGet({ pg = pgClients.client, user = {}, params = {}, query = {} }, reply) {
|
|
27
|
+
const time = [Date.now()];
|
|
27
28
|
const param = user?.uid
|
|
28
29
|
? await getToken({
|
|
29
30
|
token: params.objectid,
|
|
@@ -43,8 +44,7 @@ export default async function widgetGet({ pg = pgClients.client, user = {}, para
|
|
|
43
44
|
left join admin.users u on u.uid=c.uid
|
|
44
45
|
where entity_id=$1 order by cdate desc`
|
|
45
46
|
: "select communication_id, entity_id, body, subject, cdate, uid from crm.communications where entity_id=$1 order by cdate desc",
|
|
46
|
-
history: `
|
|
47
|
-
SELECT change_id, entity_id, entity_type, change_type, change_date, a.change_user_id, a.uid, a.cdate, b.json_agg as changes,
|
|
47
|
+
history: `SELECT change_id, entity_id, entity_type, change_type, change_date, a.change_user_id, a.uid, a.cdate, b.json_agg as changes,
|
|
48
48
|
${username} as username, u.login, u.avatar
|
|
49
49
|
FROM log.table_changes a
|
|
50
50
|
left join admin.users u on a.change_user_id = u.uid
|
|
@@ -54,26 +54,12 @@ export default async function widgetGet({ pg = pgClients.client, user = {}, para
|
|
|
54
54
|
where change_id=a.change_id
|
|
55
55
|
)q
|
|
56
56
|
)b on 1=1
|
|
57
|
-
where b.json_agg is not null and (entity_id=$1 or entity_id in (
|
|
58
|
-
select communication_id
|
|
59
|
-
union all select checklist_id from crm.checklists where entity_id=$1
|
|
57
|
+
where a.change_type != 'INSERT' and b.json_agg is not null and (entity_id=$1 or entity_id in (
|
|
58
|
+
select communication_id from crm.communications where entity_id=$1
|
|
59
|
+
union all select checklist_id from crm.checklists where entity_id=$1
|
|
60
|
+
union all select file_id from crm.files where entity_id=$1)
|
|
60
61
|
)
|
|
61
|
-
|
|
62
|
-
union all
|
|
63
|
-
select change_id, entity_id, entity_type, change_type, change_date, a.change_user_id, a.uid, a.cdate, b.json_agg as changes,
|
|
64
|
-
${username} as username, u.login, u.avatar
|
|
65
|
-
FROM log.table_changes a
|
|
66
|
-
left join admin.users u on a.change_user_id = u.uid
|
|
67
|
-
left join lateral(
|
|
68
|
-
select json_agg(o) from (
|
|
69
|
-
select json_object_agg(entity_key, coalesce(value_new, value_old)) as o from log.table_changes_data
|
|
70
|
-
where change_id=a.change_id and entity_key not in ('uid', 'file_status', 'editor_id', 'cdate', 'editor_date', 'entity_id')
|
|
71
|
-
)q
|
|
72
|
-
)b on 1=1
|
|
73
|
-
where a.change_type in ('INSERT', 'DELETE') and a.entity_id in (select file_id from crm.files where entity_id=$1)
|
|
74
|
-
limit 100
|
|
75
|
-
|
|
76
|
-
)q order by cdate desc limit 100`,
|
|
62
|
+
order by cdate desc limit 100`,
|
|
77
63
|
checklist: pg.pk["admin.users"]
|
|
78
64
|
? `SELECT checklist_id, entity_id, subject, is_done, done_date, c.uid, c.cdate, ${username} as username, u.login, u.avatar
|
|
79
65
|
FROM crm.checklists c
|
|
@@ -102,9 +88,11 @@ export default async function widgetGet({ pg = pgClients.client, user = {}, para
|
|
|
102
88
|
if (!q) {
|
|
103
89
|
return reply.status(400).send("invalid widget type");
|
|
104
90
|
}
|
|
105
|
-
/*
|
|
106
|
-
const
|
|
107
|
-
|
|
91
|
+
/* rows */
|
|
92
|
+
const rows = await pg
|
|
93
|
+
.query(q, [objectid, params.type === "gallery" ? galleryExtList : null].filter(Boolean))
|
|
94
|
+
.then((el) => el.rows || []);
|
|
95
|
+
time.push(Date.now());
|
|
108
96
|
rows.forEach((row) => Object.assign(row, { username: row.username?.trim?.() || row.login }));
|
|
109
97
|
/* reactions */
|
|
110
98
|
const widgetPkey = pkList[params.type];
|
|
@@ -121,26 +109,32 @@ export default async function widgetGet({ pg = pgClients.client, user = {}, para
|
|
|
121
109
|
});
|
|
122
110
|
}
|
|
123
111
|
/* Object info */
|
|
124
|
-
const
|
|
112
|
+
const tableName = pg.pk["log.table_changes"]
|
|
125
113
|
? await pg
|
|
126
|
-
.query(
|
|
127
|
-
.then((el) => el.rows?.[0]
|
|
114
|
+
.query("select entity_type from log.table_changes where entity_id=$1 limit 1", [objectid])
|
|
115
|
+
.then((el) => el.rows?.[0]?.entity_type)
|
|
116
|
+
: null;
|
|
117
|
+
const { pk, columns = [] } = tableName
|
|
118
|
+
? await getMeta({ pg, table: tableName })
|
|
128
119
|
: {};
|
|
129
|
-
const { pk, columns = [] } = await getMeta({ pg, table: tableName });
|
|
130
120
|
const authorIdColumn = columns.find((col) => ["uid", "created_by"].includes(col.name))?.name;
|
|
131
|
-
if (!pk &&
|
|
121
|
+
if (!pk &&
|
|
122
|
+
params.type === "history" &&
|
|
123
|
+
process.env.NODE_ENV !== "test" &&
|
|
124
|
+
!process.env.VITEST) {
|
|
132
125
|
return reply.status(404).send("log table not found");
|
|
133
126
|
}
|
|
134
127
|
const q1 = `select ${username} as author, u.login, a.cdate, a.editor_date from ${tableName} a
|
|
135
128
|
left join admin.users u on a.${authorIdColumn}=u.uid where a.${pk}=$1 limit 1`;
|
|
136
129
|
const data = pg.pk["admin.users"] && pk && tableName
|
|
137
130
|
? await pg
|
|
138
|
-
.query(
|
|
131
|
+
.query(q1, [
|
|
139
132
|
objectid,
|
|
140
133
|
params.type === "gallery" ? galleryExtList : null,
|
|
141
|
-
].filter(
|
|
134
|
+
].filter(Boolean))
|
|
142
135
|
.then((el) => el.rows?.[0] || {})
|
|
143
136
|
: {};
|
|
137
|
+
time.push(Date.now());
|
|
144
138
|
if (query.debug && user?.user_type === "admin") {
|
|
145
139
|
return {
|
|
146
140
|
q,
|
|
@@ -151,7 +145,7 @@ export default async function widgetGet({ pg = pgClients.client, user = {}, para
|
|
|
151
145
|
};
|
|
152
146
|
}
|
|
153
147
|
return reply.status(200).send({
|
|
154
|
-
time: { data:
|
|
148
|
+
time: { rows: time[1] - time[0], data: time[2] - time[1] },
|
|
155
149
|
rows,
|
|
156
150
|
user: { uid: user?.uid, name: user?.user_name },
|
|
157
151
|
data: {
|