@opengis/fastify-table 1.4.64 → 1.4.66

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengis/fastify-table",
3
- "version": "1.4.64",
3
+ "version": "1.4.66",
4
4
  "type": "module",
5
5
  "description": "core-plugins",
6
6
  "keywords": [
@@ -28,7 +28,7 @@
28
28
  "compress": "node compress.js",
29
29
  "dev1": "set NODE_ENV=dev&& node server.js",
30
30
  "dev": "node --env-file=.env.dev --env-file=.env server",
31
- "start": "node --env-file=.env.dev server"
31
+ "start": "node --env-file=.env server"
32
32
  },
33
33
  "dependencies": {
34
34
  "@aws-sdk/client-s3": "3.554.0",
@@ -34,7 +34,7 @@ function setToken({
34
34
 
35
35
  if (!Object.keys(codes).length) return { ids: 'empty' };
36
36
 
37
- rclient.hmset(`${config.pg.database}:token:edit:${uid}`, codes);
37
+ rclient.hmset(`${config.pg.database}:token:edit:${uid}`, Object.entries(codes).flat());
38
38
  // console.log(`${config.pg.database}:token:edit:${uid}`, idsOrigin, Object.values(obj));
39
39
  // TODO дополнительно писать в hset token -> uid
40
40
  return array ? Object.values(obj) : obj;
@@ -16,8 +16,8 @@ async function getHeadersPG(req, config) {
16
16
  || req.ip.startsWith('192.168.')
17
17
  || config.debug
18
18
  )
19
- && req.headers?.token
20
- && config.auth?.tokens?.includes?.(req.headers.token);
19
+ && req.headers?.token
20
+ && config.auth?.tokens?.includes?.(req.headers.token);
21
21
 
22
22
  if (validToken && req.headers?.db) {
23
23
  const pg = pgClients[req.headers.db]
@@ -32,7 +32,7 @@ async function plugin(fastify, config) {
32
32
 
33
33
  fastify.addHook('onRequest', async (req) => {
34
34
  const headersPG = await getHeadersPG(req, config);
35
- req.pg = headersPG || req.pg || client;
35
+ req.pg = headersPG || req.pg || client || pgClients.client;
36
36
  if (headersPG) {
37
37
  req.user = { uid: req.headers?.uid };
38
38
  req.folder = config.folder;
@@ -4,7 +4,7 @@ import {
4
4
 
5
5
  import extraDataGet from '../../../plugins/extra/extraDataGet.js';
6
6
 
7
- export default async function tableAPI(req, reply) {
7
+ export default async function tableAPI(req, reply, called) {
8
8
  const {
9
9
  pg = pgClients.client, params, user = {}, query = {},
10
10
  } = req;
@@ -15,14 +15,14 @@ export default async function tableAPI(req, reply) {
15
15
  });
16
16
 
17
17
  if (hookData?.message && hookData?.status) {
18
- return { message: hookData?.message, status: hookData?.status };
18
+ return reply.status(hookData?.status).send(hookData?.message);
19
19
  }
20
20
  const templateName = hookData?.table || tokenData.table || params.table;
21
21
 
22
22
  const loadTable = await getTemplate('table', templateName);
23
23
 
24
24
  if (!loadTable && !pg.pk?.[tokenData.table]) {
25
- return { message: 'not found', status: 404 };
25
+ return reply.status(404).send('not found');
26
26
  }
27
27
 
28
28
  const { table = params.table, /* columns, */ form } = hookData || loadTable || tokenData;
@@ -30,6 +30,7 @@ export default async function tableAPI(req, reply) {
30
30
  const id = hookData?.id || tokenData.id || params.id;
31
31
 
32
32
  if (tokenData && !id) return { message: {} };
33
+
33
34
  if (!table && !id) {
34
35
  return reply.status(400).send('not enough params');
35
36
  }
@@ -38,11 +39,11 @@ export default async function tableAPI(req, reply) {
38
39
  table, form, id, user,
39
40
  }, pg) || {};
40
41
 
41
- if (!tokenData && !config?.local && !config.security?.disableToken) {
42
+ if (!tokenData && !config?.local && !config.security?.disableToken && !called) {
42
43
  return reply.status(400).send('invalid token');
43
44
  }
44
45
 
45
- if (!actions.includes('edit') && !config?.local && !tokenData) {
46
+ if (!actions.includes('edit') && !config?.local && !tokenData && !called) {
46
47
  return reply.status(403).send('access restricted: actions');
47
48
  }
48
49
 
@@ -97,7 +98,7 @@ export default async function tableAPI(req, reply) {
97
98
  Object.assign(data, { [key]: extraRows });
98
99
  }));
99
100
  }
100
- if (user?.uid && !config.security?.disableToken && actions.includes('edit')) {
101
+ if (user?.uid && !config.security?.disableToken && actions.includes('edit') && !called) {
101
102
  data.token = tokenData?.table ? params.table : setToken({
102
103
  ids: [JSON.stringify({ id, table, form })],
103
104
  uid: user.uid,
@@ -1,42 +1,42 @@
1
- import { applyHook, getTemplate } from '../../../../utils.js';
2
-
3
- const sql = `select property_key as key, property_json as json, property_int as int,
4
- property_text as text from admin.properties where 1=1`;
5
-
6
- async function getSettings({ pg }) {
7
- const { rows = [] } = await pg.query(sql);
8
- const data = rows.reduce((acc, curr) => Object.assign(acc, { [curr.key]: curr.json || curr.int || curr.text }), {});
9
- return data;
10
- }
11
-
12
- export default async function formFunction(req) {
13
- const time = Date.now();
14
-
15
- const { pg, params, user } = req;
16
- const hookData = await applyHook('preForm', { form: params?.form, user });
17
-
18
- if (hookData?.message && hookData?.status) {
19
- return { message: hookData?.message, status: hookData?.status };
20
- }
21
-
22
- const form = await getTemplate('form', hookData?.form || params?.form);
23
- if (!form) { return { status: 404, message: 'not found' }; }
24
-
25
- // replace settings
26
- const arr = JSON.stringify(form).match(/{{settings.([^}]*)}}/g);
27
- if (arr?.length) {
28
- const string = JSON.stringify(form);
29
- const settings = await getSettings({ pg });
30
- const match = arr.reduce((acc, curr) => Object.assign(acc, { [curr]: settings[curr.replace(/^{{settings./g, '').replace(/}}$/, '')] }), {});
31
- const res = Object.keys(match).reduce((s, m) => s.replace(m, match[m]), string);
32
- return { time: Date.now() - time, form: JSON.parse(res) };
33
- }
34
-
35
- const res = { time: Date.now() - time, form };
36
- const res1 = await applyHook('afterForm', {
37
- form: hookData?.form || params?.form,
38
- payload: res,
39
- user,
40
- });
41
- return res1 || { time: Date.now() - time, form };
42
- }
1
+ import { applyHook, getTemplate } from '../../../../utils.js';
2
+
3
+ const sql = `select property_key as key, property_json as json, property_int as int,
4
+ property_text as text from admin.properties where 1=1`;
5
+
6
+ async function getSettings({ pg }) {
7
+ const { rows = [] } = await pg.query(sql);
8
+ const data = rows.reduce((acc, curr) => Object.assign(acc, { [curr.key]: curr.json || curr.int || curr.text }), {});
9
+ return data;
10
+ }
11
+
12
+ export default async function formFunction(req) {
13
+ const time = Date.now();
14
+
15
+ const { pg, params, user } = req;
16
+ const hookData = await applyHook('preForm', { form: params?.name, user });
17
+
18
+ if (hookData?.message && hookData?.status) {
19
+ return { message: hookData?.message, status: hookData?.status };
20
+ }
21
+
22
+ const form = await getTemplate('form', hookData?.form || params?.name);
23
+ if (!form) { return { status: 404, message: 'not found' }; }
24
+
25
+ // replace settings
26
+ const arr = JSON.stringify(form).match(/{{settings.([^}]*)}}/g);
27
+ if (arr?.length) {
28
+ const string = JSON.stringify(form);
29
+ const settings = await getSettings({ pg });
30
+ const match = arr.reduce((acc, curr) => Object.assign(acc, { [curr]: settings[curr.replace(/^{{settings./g, '').replace(/}}$/, '')] }), {});
31
+ const res = Object.keys(match).reduce((s, m) => s.replace(m, match[m]), string);
32
+ return { time: Date.now() - time, form: JSON.parse(res) };
33
+ }
34
+
35
+ const res = { time: Date.now() - time, form };
36
+ const res1 = await applyHook('afterForm', {
37
+ form: hookData?.form || params?.name,
38
+ payload: res,
39
+ user,
40
+ });
41
+ return res1 || { time: Date.now() - time, form };
42
+ }
@@ -0,0 +1,96 @@
1
+ import {
2
+ config, applyHook, getTemplate, pgClients, getAccess, setToken,
3
+ } from '../../../../utils.js';
4
+
5
+ import getEditData from '../../crud/controllers/table.js';
6
+
7
+ const q = `select
8
+ property_key as key,
9
+ property_json as json,
10
+ property_int as int,
11
+ property_text as text
12
+ from admin.properties
13
+ where 1=1`;
14
+
15
+ export default async function getForm({
16
+ pg = pgClients.client, params = {}, user = {}, query = {},
17
+ }, reply) {
18
+ const time = Date.now();
19
+ const { add, edit } = query;
20
+
21
+ const hookData = await applyHook('preForm', { table: params.name, user });
22
+
23
+ if (hookData?.message && hookData?.status) {
24
+ return reply.status(hookData?.status).send(hookData?.message);
25
+ }
26
+
27
+ const { form } = await getTemplate('table', hookData?.table || params.name) || {};
28
+
29
+ if (!form) {
30
+ return reply.status(404).send('form not found');
31
+ }
32
+
33
+ const { actions = [] } = await getAccess({ table: hookData?.table || params.name, form, user }, pg) || {};
34
+
35
+ const loadTemplate = form ? await getTemplate('form', form) : null;
36
+
37
+ if (!loadTemplate) {
38
+ return reply.status(404).send('form template not found');
39
+ }
40
+
41
+ const res = { schema: loadTemplate?.schema || loadTemplate };
42
+
43
+ if (add && user.uid) {
44
+ if (!actions.includes('add') && !config.local) {
45
+ return reply.status(403).send('access restricted: actions');
46
+ }
47
+ const addTokens = setToken({
48
+ ids: [
49
+ JSON.stringify({
50
+ table: hookData?.table || params.name,
51
+ form,
52
+ })],
53
+ uid: user.uid,
54
+ array: 1,
55
+ });
56
+ Object.assign(res, { token: addTokens[0] });
57
+ }
58
+
59
+ if (edit && user.uid) {
60
+ if (!actions.includes('edit') && !config.local) {
61
+ return reply.status(403).send('access restricted: actions');
62
+ }
63
+ const editTokens = setToken({
64
+ ids: [JSON.stringify({ id: edit, table: hookData?.table || params.name, form })],
65
+ uid: user.uid,
66
+ array: 1,
67
+ });
68
+ const data = await getEditData({
69
+ pg, params: { table: hookData?.table || params.name, id: edit }, user,
70
+ }, reply, true);
71
+ Object.assign(res, { token: editTokens[0], data });
72
+ }
73
+
74
+ // replace settings
75
+ const arr = JSON.stringify(loadTemplate).match(/{{settings.([^}]*)}}/g);
76
+
77
+ if (arr?.length) {
78
+ const string = JSON.stringify(loadTemplate);
79
+ const { rows = [] } = await pg.query(q);
80
+ const settings = rows.reduce((acc, curr) => Object.assign(acc, { [curr.key]: curr.json || curr.int || curr.text }), {});
81
+ const match = arr.reduce((acc, curr) => Object.assign(acc, { [curr]: settings[curr.replace(/^{{settings./g, '').replace(/}}$/, '')] }), {});
82
+ const result = Object.keys(match).reduce((s, m) => s.replace(m, match[m]), string);
83
+ Object.assign(res, { time: Date.now() - time, schema: JSON.parse(result) });
84
+ return res;
85
+ }
86
+
87
+ Object.assign(res, { time: Date.now() - time });
88
+
89
+ const res1 = await applyHook('afterForm', {
90
+ table: hookData?.table || params.name,
91
+ payload: res,
92
+ user,
93
+ });
94
+
95
+ return reply.status(200).send(res1 || res);
96
+ }
@@ -72,7 +72,7 @@ export default async function dataAPI(req, reply, called) {
72
72
 
73
73
  if (query.sql === '0') return loadTable;
74
74
 
75
- if (!config.pg) { return reply.status(500).send('empty pg'); }
75
+ if (!pg) { return reply.status(500).send('empty pg'); }
76
76
 
77
77
  const pkey = pg.pk?.[params?.table] || pg.pk?.[params?.table.replace(/"/g, '')];
78
78
 
@@ -108,7 +108,9 @@ export default async function dataAPI(req, reply, called) {
108
108
  logger.file('crud/warning', { msg: 'invalid filters', template: tokenData?.table || hookData?.table || params.table });
109
109
  }
110
110
 
111
- const { list: filters = [] } = await getFilter({
111
+ const objectId = tokenData?.id || hookData?.id || params.id;
112
+
113
+ const { list: filters = [] } = objectId ? {} : await getFilter({
112
114
  pg, table: tokenData?.table || hookData?.table || params.table, user,
113
115
  }) || {};
114
116
 
@@ -156,7 +158,6 @@ export default async function dataAPI(req, reply, called) {
156
158
  });
157
159
  }
158
160
 
159
- const objectId = tokenData?.id || hookData?.id || params.id;
160
161
  const isdefault = !objectId ? filters.find(el => el.default) : null;
161
162
 
162
163
  const checkFilter = [query.filter, query.search, query.state, query.custom, isdefault].filter((el) => el).length;
@@ -353,6 +354,7 @@ export default async function dataAPI(req, reply, called) {
353
354
  });
354
355
  const name = el[0].substring(0, el[0].lastIndexOf('.'));
355
356
  html[name] = htmlContent;
357
+ panels?.forEach?.(panel => panel?.items?.filter?.(item => item.name === name)?.forEach?.(el1 => Object.assign(el1, { html: htmlContent })));
356
358
  }
357
359
  catch (err) {
358
360
  const name = el[0].substring(0, el[0].lastIndexOf('.'));
@@ -398,7 +400,7 @@ export default async function dataAPI(req, reply, called) {
398
400
  }
399
401
 
400
402
  // console.log({ add: loadTable.table, form: loadTable.form });
401
- if (uid && !config.security?.disableToken && actions.includes('add')) {
403
+ if (uid && !config.security?.disableToken && actions.includes('add') && !objectId) {
402
404
  const addTokens = setToken({
403
405
  ids: [
404
406
  JSON.stringify({
@@ -9,7 +9,8 @@ import tokenInfo from './controllers/tokenInfo.js';
9
9
  import card from './controllers/card.js';
10
10
  import search from './controllers/search.js';
11
11
  import filter from './controllers/filter.js';
12
- import form from './controllers/form.js';
12
+ // import form from './controllers/form.js';
13
+ import form from './controllers/getFormByTable.js';
13
14
 
14
15
  import loadTemplatePath from '../../plugins/table/funcs/loadTemplatePath.js';
15
16
 
@@ -48,7 +49,7 @@ async function plugin(app, config = {}) {
48
49
 
49
50
  app.get(`${prefix}/templates`, () => loadTemplatePath);
50
51
  app.get(`${prefix}/filter/:table`, { config: { policy }, schema: filterSchema }, filter);
51
- app.get(`${prefix}/form/:form`, { config: { policy }, schema: formSchema }, form);
52
+ app.get(`${prefix}/form/:name`, { config: { policy }, schema: formSchema }, form);
52
53
  }
53
54
 
54
55
  export default plugin;
@@ -85,7 +85,7 @@ const formSchema = {
85
85
  type: 'object',
86
86
  properties: {
87
87
  params: {
88
- form: { type: 'string', pattern: '^([\\d\\w_.-]+)$' },
88
+ name: { type: 'string', pattern: '^([\\d\\w_.-]+)$' },
89
89
  },
90
90
  },
91
91
  };
@@ -1,106 +1,106 @@
1
- import path from 'node:path';
2
-
3
- import getMeta from '../../../plugins/pg/funcs/getMeta.js';
4
- import dataInsert from '../../../plugins/crud/funcs/dataInsert.js';
5
- import dataUpdate from '../../../plugins/crud/funcs/dataUpdate.js';
6
- import applyHook from '../../../plugins/hook/funcs/applyHook.js';
7
- import uploadMultiPart from '../../../plugins/file/uploadMultiPart.js';
8
-
9
- const tableList = {
10
- comment: 'crm.communications',
11
- gallery: 'crm.files',
12
- file: 'crm.files',
13
- checklist: 'crm.checklists',
14
- };
15
- const pkList = {
16
- comment: 'communication_id',
17
- checklist: 'checklist_id',
18
- file: 'file_id',
19
- gallery: 'file_id',
20
- };
21
-
22
- const galleryExtList = ['png', 'svg', 'jpg', 'jpeg', 'gif', 'mp4', 'mov', 'avi'];
23
-
24
- export default async function widgetSet(req, reply) {
25
- const {
26
- pg, params = {}, session = {}, headers = {}, body = {}, user = {},
27
- } = req;
28
- const { type, id, objectid } = params;
29
-
30
- if (!['comment', 'checklist', 'file', 'gallery'].includes(type)) {
31
- return reply.status(400).send('param type not valid');
32
- }
33
-
34
- if (!objectid) {
35
- return reply.status(400).send('not enough params: id');
36
- }
37
-
38
- const table = tableList[type];
39
-
40
- // dsadasdad
41
- if (['gallery', 'file'].includes(type) && headers['content-type']?.split?.(';')?.shift?.() === 'multipart/form-data') {
42
- const file = await uploadMultiPart(req);
43
- const extName = path.extname(file.filepath).slice(1).toLowerCase();
44
-
45
- const data = {
46
- uploaded_name: file?.originalFilename?.toLocaleLowerCase()?.replace(/'/g, '\'\''),
47
- file_path: file?.relativeFilepath?.replace(/\\/g, '/'),
48
- ext: extName,
49
- size: file?.size,
50
- file_status: 1,
51
- uid: user?.uid || 1,
52
- entity_id: objectid,
53
- };
54
-
55
- if (type === 'gallery' && !galleryExtList.includes(extName.toLowerCase())) {
56
- return reply.status(400).send('invalid file extension');
57
- }
58
-
59
- const { rows = [] } = await dataInsert({
60
- pg, table: 'crm.files', data, uid: user?.uid,
61
- });
62
-
63
- if (type === 'gallery') {
64
- await pg.query(`update crm.files set ismain=true
65
- where entity_id=$1
66
- and file_id=$2
67
- and (select count(*) = 0 from crm.files where entity_id=$1 and ismain)`, [objectid, rows[0]?.file_id]);
68
- }
69
-
70
- return {
71
- rowCount: 1, data: 'ok', command: 'UPLOAD', id: rows[0]?.file_id, entity_id: rows[0]?.entity_id,
72
- };
73
- }
74
- const { pk } = await getMeta({ pg, table });
75
-
76
- if (!pk) {
77
- return reply.status(404).send('table not found');
78
- }
79
-
80
- const data = { ...body, uid: user?.uid, entity_id: objectid };
81
-
82
- await applyHook('onWidgetSet', {
83
- pg,
84
- link: req.path,
85
- id,
86
- objectid,
87
- user,
88
- type,
89
- payload: data,
90
- });
91
-
92
- const result = id
93
- ? await dataUpdate({
94
- pg, table, data, id, uid: user?.uid,
95
- })
96
- : await dataInsert({
97
- pg, table, data, uid: user?.uid,
98
- });
99
-
100
- return reply.status(200).send({
101
- rowCount: result.rowCount,
102
- data: 'ok',
103
- command: result.command,
104
- id: result.rows?.[0]?.[pkList[type]] || result?.[pkList[type]],
105
- });
106
- }
1
+ import path from 'node:path';
2
+
3
+ import getMeta from '../../../plugins/pg/funcs/getMeta.js';
4
+ import dataInsert from '../../../plugins/crud/funcs/dataInsert.js';
5
+ import dataUpdate from '../../../plugins/crud/funcs/dataUpdate.js';
6
+ import applyHook from '../../../plugins/hook/funcs/applyHook.js';
7
+ import uploadMultiPart from '../../../plugins/file/uploadMultiPart.js';
8
+
9
+ const tableList = {
10
+ comment: 'crm.communications',
11
+ gallery: 'crm.files',
12
+ file: 'crm.files',
13
+ checklist: 'crm.checklists',
14
+ };
15
+ const pkList = {
16
+ comment: 'communication_id',
17
+ checklist: 'checklist_id',
18
+ file: 'file_id',
19
+ gallery: 'file_id',
20
+ };
21
+
22
+ const galleryExtList = ['png', 'svg', 'jpg', 'jpeg', 'gif', 'mp4', 'mov', 'avi'];
23
+
24
+ export default async function widgetSet(req, reply) {
25
+ const {
26
+ pg, params = {}, session = {}, headers = {}, body = {}, user = {},
27
+ } = req;
28
+ const { type, id, objectid } = params;
29
+
30
+ if (!['comment', 'checklist', 'file', 'gallery'].includes(type)) {
31
+ return reply.status(400).send('param type not valid');
32
+ }
33
+
34
+ if (!objectid) {
35
+ return reply.status(400).send('not enough params: id');
36
+ }
37
+
38
+ const table = tableList[type];
39
+
40
+ // dsadasdad
41
+ if (['gallery', 'file'].includes(type) && headers['content-type']?.split?.(';')?.shift?.() === 'multipart/form-data') {
42
+ const file = await uploadMultiPart(req);
43
+ const extName = path.extname(file.filepath).slice(1).toLowerCase();
44
+
45
+ const data = {
46
+ uploaded_name: file?.originalFilename?.toLocaleLowerCase()?.replace(/'/g, '\'\''),
47
+ file_path: file?.relativeFilepath?.replace(/\\/g, '/'),
48
+ ext: extName,
49
+ size: file?.size,
50
+ file_status: 1,
51
+ uid: user?.uid || 1,
52
+ entity_id: objectid,
53
+ };
54
+
55
+ if (type === 'gallery' && !galleryExtList.includes(extName.toLowerCase())) {
56
+ return reply.status(400).send('invalid file extension');
57
+ }
58
+
59
+ const { rows = [] } = await dataInsert({
60
+ pg, table: 'crm.files', data, uid: user?.uid,
61
+ });
62
+
63
+ if (type === 'gallery') {
64
+ await pg.query(`update crm.files set ismain=true
65
+ where entity_id=$1
66
+ and file_id=$2
67
+ and (select count(*) = 0 from crm.files where entity_id=$1 and ismain)`, [objectid, rows[0]?.file_id]);
68
+ }
69
+
70
+ return {
71
+ rowCount: 1, data: 'ok', command: 'UPLOAD', id: rows[0]?.file_id, entity_id: rows[0]?.entity_id,
72
+ };
73
+ }
74
+ const { pk } = await getMeta({ pg, table });
75
+
76
+ if (!pk) {
77
+ return reply.status(404).send('table not found');
78
+ }
79
+
80
+ const data = { ...body, uid: user?.uid, entity_id: objectid };
81
+
82
+ await applyHook('onWidgetSet', {
83
+ pg,
84
+ link: req.path,
85
+ id,
86
+ objectid,
87
+ user,
88
+ type,
89
+ payload: data,
90
+ });
91
+
92
+ const result = id
93
+ ? await dataUpdate({
94
+ pg, table, data, id, uid: user?.uid,
95
+ })
96
+ : await dataInsert({
97
+ pg, table, data, uid: user?.uid,
98
+ });
99
+
100
+ return reply.status(200).send({
101
+ rowCount: result.rowCount,
102
+ data: 'ok',
103
+ command: result.command,
104
+ id: result.rows?.[0]?.[pkList[type]] || result?.[pkList[type]],
105
+ });
106
+ }