@opengis/admin 0.1.78 → 0.1.80

Sign up to get free protection for your applications and to get access to all the features.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengis/admin",
3
- "version": "0.1.78",
3
+ "version": "0.1.80",
4
4
  "description": "This project Softpro Admin",
5
5
  "main": "dist/admin.js",
6
6
  "type": "module",
@@ -35,7 +35,7 @@
35
35
  "@opengis/admin": "^0.1.69",
36
36
  "@opengis/fastify-auth": "^1.0.44",
37
37
  "@opengis/fastify-file": "^1.0.27",
38
- "@opengis/fastify-table": "^1.1.59",
38
+ "@opengis/fastify-table": "^1.1.60",
39
39
  "@opengis/v3-core": "^0.2.36",
40
40
  "@opengis/v3-filter": "^0.0.39",
41
41
  "@tiptap/core": "^2.8.0",
@@ -0,0 +1,16 @@
1
+ import { config, setToken } from "@opengis/fastify-table/utils.js";
2
+
3
+ export default function token(params) {
4
+ const { data, hash } = params;
5
+ if (!hash || typeof hash !== 'object') return '-';
6
+
7
+ const id = hash?.edit ? hash?.id : data?.root?.id;
8
+
9
+ const [token] = setToken({
10
+ ids: [JSON.stringify({ ...hash, id })],
11
+ mode: hash?.edit ? 'w' : 'a',
12
+ uid: config?.auth?.disable ? '1' : data?.root?.user?.uid,
13
+ array: 1,
14
+ });
15
+ return token;
16
+ }
@@ -3,6 +3,7 @@ import _vue from "./controllers/vue.js";
3
3
  import map from "./controllers/map.js";
4
4
  import _mls from "./controllers/mls.js";
5
5
  import badge from "./controllers/badge.js";
6
+ import token from "./controllers/token.js";
6
7
 
7
8
  import { handlebars } from "@opengis/fastify-table/utils.js";
8
9
 
@@ -12,4 +13,5 @@ export default async function route(fastify) {
12
13
  handlebars.registerHelper('map', map);
13
14
  handlebars.registerHelper('mls', _mls);
14
15
  handlebars.registerHelper('badge', badge);
16
+ handlebars.registerHelper('token', token);
15
17
  }
@@ -17,8 +17,12 @@ export default async function plugin(fastify) {
17
17
  const json = await getMenu({ user: { uid: 1 } });
18
18
  // insert interface list to db (user access management)
19
19
  if (client?.pk?.['admin.routes'] && json?.length) {
20
- const menuList = json.filter((el) => el?.menu?.length && el?.ua || el?.en || el?.name);
21
- const interfaces = menuList.reduce((acc, curr) => { curr.menu?.forEach((el) => acc.push(el.path)); return acc; }, []);
20
+ const menuList = json.filter((el) => (el?.table || el?.menu?.length) && el?.ua || el?.en || el?.name);
21
+ const interfaces = menuList.reduce((acc, curr) => {
22
+ if (curr.table) { acc.push(curr.path); }
23
+ curr.menu?.forEach((el) => acc.push(el.path));
24
+ return acc;
25
+ }, []);
22
26
  await client.query('update admin.routes set enabled=false where not array[route_id] <@ $1::text[]', [interfaces]);
23
27
 
24
28
  const q = `insert into admin.menu(name, ord) values${menuList.map((el, i) => `('${(el?.ua || el?.en || el?.name).replace(/'/g, '’')}', ${i}) `).join(',')
@@ -27,7 +31,11 @@ export default async function plugin(fastify) {
27
31
  await client.query('update admin.menu set enabled=false where not array[menu_id] <@ $1::text[]', [rows.map((el) => el.menu_id)]);
28
32
 
29
33
  const menus = rows.reduce((acc, curr) => Object.assign(acc, { [curr.menu_id]: menuList.find((item) => (item?.ua || item?.en || item?.name) === curr.name) }), {});
30
- const values = Object.entries(menus).reduce((acc, curr) => { curr[1]?.menu?.forEach((el) => acc.push({ ...el, menuId: curr[0] })); return acc; }, []);
34
+ const values = Object.entries(menus).reduce((acc, curr) => {
35
+ if (curr[1]?.table) { acc.push({ ...curr[1], menuId: curr[0] }); }
36
+ curr[1]?.menu?.forEach((el) => acc.push({ ...el, menuId: curr[0] }));
37
+ return acc;
38
+ }, []);
31
39
 
32
40
  await Promise.all(values.filter((el) => el?.table).map(async (el) => {
33
41
  const loadTable = await getTemplate('table', el.table);
@@ -38,11 +46,12 @@ export default async function plugin(fastify) {
38
46
  });
39
47
  }));
40
48
 
41
- const q1 = `insert into admin.routes(route_id, alias, title, menu_id, table_name, actions, access)
42
- values ${values.map((el) => `('${el.path}', '${el.table}', ${(el.title || el.ua) ? `'${el.title || el.ua}'` : 'null'}, '${el.menuId}', '${el.table1}',
43
- ${el.actions?.length ? `'{ ${el.actions} }'::text[]` : 'null'}, ${el.access ? `'${el.access}'` : 'null'})`).join(',')}
44
- on conflict (route_id) do update set menu_id=excluded.menu_id, alias=excluded.alias, title=excluded.title, enabled=true,
45
- table_name=excluded.table_name, actions=excluded.actions, access=excluded.access returning route_id, table_name`;
49
+ const q1 = `insert into admin.routes(route_id, alias, title, menu_id, table_name, actions, access, query)
50
+ values ${values.filter((el) => el?.table).map((el) => `('${el.path}', '${el.table}', ${(el.title || el.ua) ? `'${el.title || el.ua}'` : 'null'}, '${el.menuId || null}', '${el.table1}',
51
+ ${el.actions?.length ? `'{ ${el.actions} }'::text[]` : 'null'}, ${el.access ? `'${el.access}'` : 'null'}, ${el.query ? `'${el.query.replace(/'/g,"''")}'` : '\'1=1\''})`).join(',')}
52
+ on conflict (route_id) do update set menu_id=excluded.menu_id, alias=excluded.alias, title=excluded.title, enabled=true, query=excluded.query,
53
+ table_name=excluded.table_name, actions=excluded.actions, access=excluded.access returning route_id, table_name`;
54
+
46
55
  try {
47
56
  const { rowCount } = values?.length ? await client.query(q1) : {};
48
57
  console.log('interface insert ok', /* values, */ rowCount);
@@ -10,80 +10,79 @@ export default async function calendarData({
10
10
  }
11
11
  const { date, sql } = query;
12
12
 
13
- try {
14
- const body = await getTemplate('calendar', name);
15
13
 
16
- if (!body) {
17
- return { message: `calendar not found: ${name}`, status: 404 };
18
- }
14
+ const body = await getTemplate('calendar', name);
19
15
 
20
- const {
21
- title,
22
- table,
23
- query: query1 = '1=1',
24
- meta = {},
25
- filter = [],
26
- } = body;
16
+ if (!body) {
17
+ return { message: `calendar not found: ${name}`, status: 404 };
18
+ }
19
+
20
+ const {
21
+ title,
22
+ table,
23
+ query: query1 = '1=1',
24
+ meta = {},
25
+ filter = [],
26
+ } = body;
27
27
 
28
- if (!table) {
29
- return { message: 'not enough calendar params: table', status: 404 };
30
- }
31
- if (!pg.pk?.[table]) {
32
- return { message: `table pkey not found: ${table}`, status: 404 };
33
- }
28
+ if (!table) {
29
+ return { message: 'not enough calendar params: table', status: 404 };
30
+ }
31
+ if (!pg.pk?.[table]) {
32
+ return { message: `table pkey not found: ${table}`, status: 404 };
33
+ }
34
34
 
35
- const filterWhere = filter?.length && query.filter?.length
36
- ? filter.filter((el) => (Object.hasOwn(el, 'enabled') ? el?.enabled : true))
37
- .map((el) => {
38
- const val = query.filter.split(',').find((e) => e?.split('=')?.shift()?.includes(el.column || el.name))?.split('=')?.pop();
39
- if (val) return el.column && val ? `(${[`${el.column}::text='${val.replace(/'/g,"''")}'::text`, el.query].filter((el) => el).join(' and ')})` : el.query;
40
- }).filter((el) => el).join(' and ')
41
- : undefined;
42
- // console.log(filterWhere);
35
+ const filterWhere = filter?.length && query.filter?.length
36
+ ? filter.filter((el) => (Object.hasOwn(el, 'enabled') ? el?.enabled : true))
37
+ .map((el) => {
38
+ const val = query.filter.split(',').find((e) => e?.split('=')?.shift()?.includes(el.column || el.name))?.split('=')?.pop();
39
+ if (val) return el.column && val ? `(${[`${el.column}::text='${val.replace(/'/g,"''")}'::text`, el.query].filter((el) => el).join(' and ')})` : el.query;
40
+ }).filter((el) => el).join(' and ')
41
+ : undefined;
42
+ // console.log(filterWhere);
43
43
 
44
44
  const queryWhere = await handlebars.compile(query1)({ uid });
45
45
  const filterDate = date ? `date_trunc('month', "${meta?.date || meta?.start}"::date)='${date}'::date` : undefined;
46
46
  const where = [queryWhere, filterDate, filterWhere].filter((el) => el).join(' and ');
47
47
 
48
- const filtersByColumn = filter.filter((el) => (Object.hasOwn(el, 'enabled') ? el?.enabled : true) && el?.column);
49
-
50
- const filters = [];
51
- if (filtersByColumn?.length) {
52
- await Promise.all(filtersByColumn.map(async (el) => {
53
- const { rows: filterData = [] } = await pg.query(`select "${el.column}" as id, count(*) from ${table}
54
- where ${el.query || '1=1'} and ${filterWhere || '1=1'} group by "${el.column}"`);
55
- if (!filterData?.length) return;
56
-
57
- // const clsData = await getSelectVal({ pg, name: el.cls, values: filterData.map((el) => el.id) });
58
- const clsData = el.cls ? await getTemplate(['cls', 'select'], el.cls) : undefined;
59
-
60
- if (!el.cls) {
61
- filterData.forEach((el1) => filters.push(el1));
62
- return;
63
- }
48
+ const filtersByColumn = filter.filter((el) => (Object.hasOwn(el, 'enabled') ? el?.enabled : true) && el?.column);
49
+
50
+ const filters = [];
51
+ if (filtersByColumn?.length) {
52
+ await Promise.all(filtersByColumn.map(async (el) => {
53
+ const { rows: filterData = [] } = await pg.query(`select $1 as id, count(*) from $2
54
+ where ${el.query || '1=1'} and ${filterWhere || '1=1'} group by $1`, [el.column, table] );
55
+ if (!filterData?.length) return;
56
+
57
+ // const clsData = await getSelectVal({ pg, name: el.cls, values: filterData.map((el) => el.id) });
58
+ const clsData = el.cls ? await getTemplate(['cls', 'select'], el.cls) : undefined;
59
+
60
+ if (!el.cls) {
61
+ filterData.forEach((el1) => filters.push(el1));
62
+ return;
63
+ }
64
64
 
65
- filterData.forEach((el1) => {
66
- const cls = clsData.find((item) => item.id === el1.id.toString());
67
- Object.assign(el1, { title: cls?.text, color: cls?.color });
68
- filters.push(el1);
69
- });
70
- }));
71
- }
65
+ filterData.forEach((el1) => {
66
+ const cls = clsData.find((item) => item.id === el1.id.toString());
67
+ Object.assign(el1, { title: cls?.text, color: cls?.color });
68
+ filters.push(el1);
69
+ });
70
+ }));
71
+ }
72
72
 
73
- const tableMeta = await getMeta({ pg, table });
74
- const columnList = tableMeta?.columns?.map((el) => el?.name);
75
- const columns = Object.keys(meta).filter((el) => ['date', 'start','end','title','status'].includes(el) && columnList.includes(meta[el])).map((el) => `"${meta[el]}" as ${el}`);
76
-
77
- if (!columns?.length) {
78
- return { message: `calendar param meta is invalid: invalid/empty keys`, status: 404 };
79
- }
73
+ const tableMeta = await getMeta({ pg, table });
74
+ const columnList = tableMeta?.columns?.map((el) => el?.name);
75
+ const columns = Object.keys(meta).filter((el) => ['date', 'start','end','title','status'].includes(el) && columnList.includes(meta[el])).map((el) => `"${meta[el]}" as ${el}`);
76
+
77
+ if (!columns?.length) {
78
+ return { message: `calendar param meta is invalid: invalid/empty keys`, status: 404 };
79
+ }
80
80
 
81
- const q = `select ${columns.join(',')} from ${table} where ${where}`;
82
- if (sql) return q;
81
+ const q = `select &1 from $2 where $3`;
82
+ if (sql) return q;
83
+
84
+ const { rows = [] } = await pg.query(q, [columns.join(','), table, where]);
85
+
86
+ return { title, filters, rows };
83
87
 
84
- const { rows = [] } = await pg.query(q);
85
- return { title, filters, rows };
86
- } catch (err) {
87
- return { error: err.toString(), status: 500 };
88
- }
89
88
  }
@@ -1,3 +1,5 @@
1
+ import path from 'node:path';
2
+
1
3
  import { config, handlebars, setToken, getTemplate } from "@opengis/fastify-table/utils.js";
2
4
  // import yaml from 'js-yaml';
3
5
  import getTableData from "./tableData.js";
@@ -7,7 +9,7 @@ export default async function getCardData(req) {
7
9
  pg, params = {}, session = {}, user
8
10
  } = req;
9
11
  const { table, id } = params;
10
- const { uid } = session.passport?.user || {};
12
+ const uid = config?.auth?.disable ? '1' : session.passport?.user?.uid;
11
13
 
12
14
  const time = Date.now();
13
15
 
@@ -16,9 +18,23 @@ export default async function getCardData(req) {
16
18
  const tableTemplate = await getTemplate('table', table);
17
19
  const index = template?.find(el => el[0] === 'index.yml')?.[1] || {};
18
20
 
19
- if (index?.tokens) {
20
- console.log('hit');
21
+ if (index?.tokens && typeof index?.tokens === 'object' && !Array.isArray(index?.tokens)) {
22
+ Object.keys(index?.tokens).map((key) => {
23
+ const id1 = index.tokens[key]?.edit ? index.tokens[key]?.id : id;
24
+ const [token] = setToken({
25
+ ids: [JSON.stringify({ ...index.tokens[key], id: id1 })],
26
+ mode: index.tokens[key]?.edit ? 'w' : 'a',
27
+ uid,
28
+ array: 1,
29
+ });
30
+ index.tokens[key] = token;
31
+ });
21
32
  }
33
+
34
+ const vue = template
35
+ .filter((el) => el[0].endsWith('.vue'))
36
+ .reduce((acc, curr) => Object.assign(acc, { [path.parse(curr[0]).name]: curr[1].match(/<template[^>]*>([\s\S]*?)<\/template>/)[1].trim() }), {});
37
+
22
38
  if (index?.panels?.length) {
23
39
  index?.panels.filter((el) => el.props || el.items?.find((item) => item.props))?.forEach((panel) => {
24
40
  if (panel.props) {
@@ -45,18 +61,35 @@ export default async function getCardData(req) {
45
61
  }
46
62
 
47
63
  const data = {};
64
+ if (index?.data && index?.data?.[0]?.name) {
65
+ await Promise.all(index.data.filter((el) => el?.name && el?.sql).map(async (el) => {
66
+ const q = await handlebars.compile(el.sql)({ user, uid: user?.uid, id });
67
+ const { rows = [] } = await pg.query(q);
68
+ data[el.name] = rows;
69
+ }));
70
+ }
71
+
48
72
  const { message, rows = [] } = await getTableData({ pg, params: { table, id }, session, user });
49
73
 
50
74
  if (message) return { message };
51
75
 
76
+ const html = {};
52
77
  if (template) {
53
78
  await Promise.all(template.filter(el => el[0].includes('.hbs')).map(async (el) => {
54
- const htmlContent = await handlebars.compile(el[1])(rows[0]);
79
+ const htmlContent = await handlebars.compile(el[1])({ ...rows[0], user });
55
80
  const name = el[0].substring(0, el[0].lastIndexOf('.'))
56
- data[name] = htmlContent;
81
+ html[name] = htmlContent;
57
82
  }));
58
83
  }
59
84
 
60
- return { time: Date.now() - time, ...index, data, rows, columns: tableTemplate?.columns || tableTemplate?.colModel };
85
+ return {
86
+ time: Date.now() - time,
87
+ ...index,
88
+ vue,
89
+ data,
90
+ html,
91
+ rows,
92
+ columns: tableTemplate?.columns || tableTemplate?.colModel,
93
+ };
61
94
 
62
95
  }
@@ -1,10 +1,13 @@
1
-
2
1
  import getData from '@opengis/fastify-table/server/routes/table/controllers/data.js';
3
2
  // import getData from '../../../../../../npm/fastify-table/server/routes/table/controllers/data.js';
4
3
 
5
4
  export default async function getTableData(req) {
6
5
  //const time = Date.now();
7
- req.params.query = '1=1'
6
+ const interfaceName = req.headers?.referer?.match(/.*\/([^?]+)/)?.[1];
7
+ const { query = '1=1' } = interfaceName ? await req.pg.query(`select query from admin.routes where route_id=$1`, [interfaceName])
8
+ .then((res1) => res1.rows?.[0] || {}) : {};
9
+
10
+ req.params.query = query;
8
11
  const res = await getData(req);
9
12
 
10
13
  return res;
@@ -34,7 +34,7 @@ export default async function tableFilter(req) {
34
34
  if (!cls?.length || !Array.isArray(cls) || !loadTable.table || !name) return;
35
35
  const { dataTypeID } = columns.find((item) => item?.name === name) || {};
36
36
  if (el.extra && el.type === 'select' && Array.isArray(cls)) {
37
- const countArr = await pg.query(`select value_text as id, count(*) from crm.extra_data where property_key='${name}' and property_entity='${params.name}' group by value_text`);
37
+ const countArr = await pg.query(`select value_text as id, count(*) from crm.extra_data where property_key=$1 and property_entity=$2 group by value_text`, [name, params.name]);
38
38
  const options = countArr.rows.map(cel => {
39
39
  const data = cls.find(c => c.id === cel.id);
40
40
  return { ...cel, ...data };
@@ -2,10 +2,10 @@ const tableDataSchema = {
2
2
  querystring: {
3
3
  limit: { type: 'string', pattern: '^(\\d+)$' },
4
4
  page: { type: 'string', pattern: '^(\\d+)$' },
5
- filter: { type: 'string', pattern: '^([А-Яа-яҐґЄєІіЇї\\d\\w\\s(),.!?;:—_=-]+)$' },
6
- search: { type: 'string', pattern: '^[А-Яа-яҐґЄєІіЇї\\d\\w\\s(),.!?;:—_=-]+$' },
5
+ // filter: { type: 'string', pattern: '^([\\w\\d_-]+)=([А-Яа-яҐґЄєІіЇї\\d\\w\\s\\/\\[\\]\\(\\)\\{\\}\\|,.!?;:—_=-@%#$&^*+=`~]+)$' },
6
+ // search: { type: 'string', pattern: '^([А-Яа-яҐґЄєІіЇї\\d\\w\\s\\/\\[\\]\\(\\)\\{\\}\\|,.!?;:—_=-@%#$&^*+=`~]+)$' },
7
7
  order: { type: 'string', pattern: '^([\\d\\w_.-]+)$' },
8
- desc: { type: 'string', pattern: '^(desc)|(asc)$' },
8
+ desc: { type: 'string', pattern: '^(\\d+)$' },
9
9
  state: { type: 'string', pattern: '^([\\d\\w._-]+)$' },
10
10
  custom: { type: 'string', pattern: '^([\\d\\w._-]+)$' },
11
11
  bbox: { type: 'string', pattern: '^([\\d\\s,.-]+)$' },
@@ -31,16 +31,12 @@ export default async function userNotifications({
31
31
  const limit = Math.min(maxLimit, +(query.limit || 5));
32
32
  const offset = query.page && query.page > 0 ? (query.page - 1) * limit : 0;
33
33
 
34
-
35
-
36
-
37
-
38
34
  const q = `select notification_id as id, subject, body, cdate,
39
- author_id, read, link, entity_id, (select avatar from admin.users where uid=a.author_id limit 1) as avatar from crm.notifications a where addressee_id=$1 order by cdate desc limit ${limit} offset ${offset}`;
35
+ author_id, read, link, entity_id, (select avatar from admin.users where uid=a.author_id limit 1) as avatar from crm.notifications a where addressee_id=$1 order by cdate desc limit $2 offset $3`;
40
36
 
41
37
  if (query.sql) return q;
42
38
 
43
- const { rows = [] } = await pg.query(q, [uid]);
39
+ const { rows = [] } = await pg.query(q, [uid, limit, offset]);
44
40
 
45
41
  const values = rows.map((el) => el.author_id)
46
42
  ?.filter((el, idx, arr) => el && arr.indexOf(el) === idx);
@@ -22,13 +22,9 @@ export default async function getUserProperties({
22
22
  const cache = await redis.get(keyCache);
23
23
  if (cache) return JSON.parse(cache);
24
24
 
25
- try {
26
- const res = await getSettings({
27
- pg, key: params.key, json: query.json, redis, table, uid,
28
- });
29
- return { message: res, status: 200 };
30
- }
31
- catch (err) {
32
- return { error: err.toString(), status: 500 };
33
- }
25
+ const res = await getSettings({
26
+ pg, key: params.key, json: query.json, redis, table, uid,
27
+ });
28
+
29
+ return { message: res, status: 200 };
34
30
  }
@@ -1,8 +1,10 @@
1
1
  import getTemplateApi from './controllers/getTemplate.js';
2
2
 
3
+ import getTemplateSchema from './schema.js'
4
+
3
5
  export default async function route(fastify) {
4
6
  //fastify.decorate('addTempateFolder', addTempateFolder); // call from funcs
5
- fastify.get(`/template/:type/:name`, getTemplateApi);
7
+ fastify.get(`/template/:type/:name`, { scheme: getTemplateSchema }, getTemplateApi);
6
8
 
7
9
  /*fastify.addHook('onListen', async () => {
8
10
  await addTempateFolder(path.join(process.cwd(), '/module/itree'));
@@ -2,38 +2,10 @@ import widgetDel from './controllers/widget.del.js';
2
2
  import widgetSet from './controllers/widget.set.js';
3
3
  import widgetGet from './controllers/widget.get.js';
4
4
 
5
- const tableSchema = {
6
- params: {
7
- // type: { type: 'string', pattern: '^([\\d\\w]+)$' },
8
- objectid: { type: 'string', pattern: '^([\\d\\w]+)$' },
9
- id: { type: 'string', pattern: '^([\\d\\w]+)$' },
10
- },
11
- querystring: {
12
- debug: { type: 'string', pattern: '^(\\d+)$' },
13
- },
14
- };
5
+ import {tableSchema} from './schema.js'
15
6
 
16
- async function route(fastify, opt) {
17
- fastify.route({
18
- method: 'DELETE',
19
- url: '/widget/:type/:objectid/:id',
20
- schema: tableSchema,
21
- handler: widgetDel,
22
- });
23
- fastify.route({
24
- method: 'POST',
25
- path: '/widget/:type/:objectid/:id?',
26
- schema: tableSchema,
27
- handler: widgetSet,
28
- });
29
- fastify.route({
30
- method: 'GET',
31
- path: '/widget/:type/:objectid',
32
- config: {
33
- policy: ['public'],
34
- },
35
- schema: tableSchema,
36
- handler: widgetGet,
37
- });
7
+ export default async function route(fastify) {
8
+ fastify.delete(`widget/:type/:objectid/:id`, { scheme: tableSchema }, widgetDel);
9
+ fastify.post(`/widget/:type/:objectid/:id?`, { scheme: tableSchema }, widgetSet);
10
+ fastify.get(`/widget/:type/:objectid`, { config: { policy: ['public'] }, scheme: tableSchema }, widgetGet);
38
11
  }
39
- export default route;
@@ -0,0 +1,13 @@
1
+ const tableSchema = {
2
+ params: {
3
+ // type: { type: 'string', pattern: '^([\\d\\w]+)$' },
4
+ objectid: { type: 'string', pattern: '^([\\d\\w]+)$' },
5
+ id: { type: 'string', pattern: '^([\\d\\w]+)$' },
6
+ },
7
+ querystring: {
8
+ debug: { type: 'string', pattern: '^(\\d+)$' },
9
+ },
10
+ };
11
+
12
+ export default null;
13
+ export { tableSchema }