@opengis/fastify-table 1.4.83 → 1.4.85

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.
Files changed (27) hide show
  1. package/index.js +30 -9
  2. package/package.json +2 -2
  3. package/server/helpers/core/token.js +18 -18
  4. package/server/migrations/crm.sql +11 -1
  5. package/server/plugins/cron/funcs/addCron.js +52 -52
  6. package/server/plugins/crud/funcs/getOpt.js +14 -14
  7. package/server/plugins/crud/funcs/utils/getFolder.js +11 -11
  8. package/server/plugins/logger/errorStatus.js +19 -19
  9. package/server/plugins/redis/client.js +8 -8
  10. package/server/plugins/redis/funcs/redisClients.js +3 -3
  11. package/server/plugins/sqlite/funcs/getSqlite.js +8 -3
  12. package/server/plugins/sqlite/funcs/init.js +1 -1
  13. package/server/plugins/sqlite/sqliteClients.js +8 -3
  14. package/server/plugins/table/funcs/getFilterSQL/util/getCustomQuery.js +13 -13
  15. package/server/plugins/table/funcs/getFilterSQL/util/getTableSql.js +34 -34
  16. package/server/plugins/table/funcs/getTemplates.js +19 -19
  17. package/server/plugins/table/funcs/gisIRColumn.js +82 -82
  18. package/server/plugins/table/funcs/loadTemplate.js +1 -1
  19. package/server/plugins/table/funcs/loadTemplatePath.js +1 -1
  20. package/server/plugins/table/funcs/userTemplateDir.js +1 -1
  21. package/server/routes/table/controllers/getFormByTable.js +1 -1
  22. package/server/routes/table/controllers/search.js +74 -74
  23. package/server/routes/widget/controllers/widget.del.js +99 -89
  24. package/server/routes/widget/controllers/widget.get.js +1 -1
  25. package/server/routes/widget/controllers/widget.set.js +4 -2
  26. package/server/routes/widget/hook/onWidgetSet.js +13 -13
  27. package/server/routes/widget/index.mjs +38 -38
package/index.js CHANGED
@@ -9,6 +9,7 @@ import proxy from '@fastify/http-proxy';
9
9
  import config from './config.js';
10
10
 
11
11
  const { maxFileSize = 512 } = config;
12
+ const { name: execName } = path.parse(process.argv0);
12
13
 
13
14
  // helpers
14
15
  // import helperPlugin from './server/helpers/index.js';
@@ -117,15 +118,35 @@ async function plugin(fastify, opt) {
117
118
  }
118
119
 
119
120
  config.proxy?.forEach?.(el => {
120
- fastify.register(proxy, {
121
- upstream: el.target,
122
- prefix: el.source,
123
- http2: false,
124
- preHandler: async (req) => {
125
- req.headers.uid = req.session?.passport?.user?.uid;
126
- Object.keys(el.headers || {})?.forEach(item => req.headers[item] = el.headers[item]);
127
- },
128
- });
121
+ if (execName === 'bun') {
122
+ fastify.all(`${el.source}/*`, async (req, reply) => {
123
+ const url = el.target.replace(/\/$/, '') + req.raw.url.replace(new RegExp(`^${el.source}`), '');
124
+ const res = await fetch(url, {
125
+ method: req.method,
126
+ headers: {
127
+ // ...req.headers,
128
+ uid: req.user?.uid,
129
+ ...(el.headers || {}),
130
+ },
131
+ body: ['PUT', 'POST'].includes(req.method) ? req.raw : undefined,
132
+ });
133
+ const resp = res.headers.get('content-type')?.includes('/json') ? await res.json() : await res.text();
134
+ reply.headers(Object.fromEntries(res.headers));
135
+ reply.status(res.status);
136
+ reply.send(resp);
137
+ });
138
+ }
139
+ else {
140
+ fastify.register(proxy, {
141
+ upstream: el.target,
142
+ prefix: el.source,
143
+ http2: false,
144
+ preHandler: async (req) => {
145
+ req.headers.uid = req.session?.passport?.user?.uid;
146
+ Object.keys(el.headers || {})?.forEach(item => req.headers[item] = el.headers[item]);
147
+ },
148
+ });
149
+ }
129
150
  });
130
151
 
131
152
  if (config.dblist) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengis/fastify-table",
3
- "version": "1.4.83",
3
+ "version": "1.4.85",
4
4
  "type": "module",
5
5
  "description": "core-plugins",
6
6
  "keywords": [
@@ -61,4 +61,4 @@
61
61
  },
62
62
  "author": "Softpro",
63
63
  "license": "ISC"
64
- }
64
+ }
@@ -1,18 +1,18 @@
1
- import setToken from '../../plugins/crud/funcs/setToken.js';
2
-
3
- export default function tokenFunc(params) {
4
- const { data, hash } = params;
5
-
6
- if (!data?.root?.user?.uid && !hash.uid) return '-';
7
- if (!hash || typeof hash !== 'object') return '-';
8
-
9
- // const id = hash?.edit ? hash?.id : data?.root?.id;
10
- // console.log(hash)
11
- const [token] = setToken({
12
- ids: [JSON.stringify(hash)],
13
-
14
- uid: data?.root?.user?.uid || hash.uid,
15
- array: 1,
16
- });
17
- return token;
18
- }
1
+ import setToken from '../../plugins/crud/funcs/setToken.js';
2
+
3
+ export default function tokenFunc(params) {
4
+ const { data, hash } = params;
5
+
6
+ if (!data?.root?.user?.uid && !hash.uid) return '-';
7
+ if (!hash || typeof hash !== 'object') return '-';
8
+
9
+ // const id = hash?.edit ? hash?.id : data?.root?.id;
10
+ // console.log(hash)
11
+ const [token] = setToken({
12
+ ids: [JSON.stringify(hash)],
13
+
14
+ uid: data?.root?.user?.uid || hash.uid,
15
+ array: 1,
16
+ });
17
+ return token;
18
+ }
@@ -124,7 +124,7 @@ COMMENT ON COLUMN crm.properties.table_name IS 'Таблиця';
124
124
  ALTER TABLE crm.properties ADD COLUMN IF NOT EXISTS object_id text;
125
125
  COMMENT ON COLUMN crm.properties.object_id IS 'ID Об''єкту';
126
126
  ALTER TABLE crm.properties ADD COLUMN IF NOT EXISTS property_key text;
127
- COMMENT ON COLUMN crm.properties.object_id IS 'Назва атрибуту';
127
+ COMMENT ON COLUMN crm.properties.property_key IS 'Назва атрибуту';
128
128
  ALTER TABLE crm.properties ADD COLUMN IF NOT EXISTS property_text text;
129
129
  COMMENT ON COLUMN crm.properties.property_text IS 'Текст';
130
130
  ALTER TABLE crm.properties ADD COLUMN IF NOT EXISTS property_int integer;
@@ -143,3 +143,13 @@ ALTER TABLE crm.properties ADD COLUMN IF NOT EXISTS cdate timestamp without time
143
143
  ALTER TABLE crm.properties ADD COLUMN IF NOT EXISTS files json;
144
144
 
145
145
  ALTER TABLE crm.properties ADD CONSTRAINT crm_properties_pkey PRIMARY KEY(property_id);
146
+
147
+ -- drop table if exists crm.reactions;
148
+ CREATE TABLE if not exists crm.reactions (
149
+ reaction_id text default next_id() PRIMARY KEY,
150
+ created_by text NOT NULL,
151
+ entity_id text NOT NULL,
152
+ reaction_type text NOT NULL check (reaction_type in ('like', 'love', 'hate', 'wow', 'sad', 'angry')),
153
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
154
+ FOREIGN KEY (user_id) REFERENCES admin.users(uid)
155
+ );
@@ -1,52 +1,52 @@
1
- import config from '../../../../config.js';
2
-
3
- import logger from '../../logger/getLogger.js';
4
- import pgClients from '../../pg/pgClients.js';
5
-
6
- import cronList from '../cronList.js';
7
- import runCron from './runCron.js';
8
- import interval2ms from './interval2ms.js';
9
-
10
- /**
11
- * interval:
12
- * - 02:54 - every day
13
- * - 2:03 - every day
14
- * - *1:43 - 2 times a day
15
- * - *12:03 - 2 times a day
16
- * - **:54 - every hour
17
- * - **:*3 - every 10 minutes
18
- * - 60 - every minute
19
- * - 10 * 60 - every 10 minutes
20
- */
21
-
22
- export default async function addCron(func, interval, pg = pgClients.client) {
23
- const { time = {}, disabled = [] } = config.cron || {};
24
-
25
- const name = func.name || func.toString().split('/').at(-1).split('\'')[0];
26
-
27
- // if (!config.isServer) return;
28
-
29
- if (disabled.includes(name)) {
30
- logger.file('cron', { name, message: 'cron disabled' });
31
- return;
32
- }
33
-
34
- cronList[name] = func;
35
-
36
- const userInterval = time[name] || interval;
37
- const [waitMs, intervalMs] = interval2ms[typeof interval](userInterval);
38
-
39
- if (intervalMs < 1000) {
40
- logger.file('cron', { name, error: `interval ${interval} too small` });
41
- return;
42
- }
43
-
44
- // setTimeout to w8 for the time to start
45
- setTimeout(() => {
46
- runCron({ pg, func, name });
47
- // interval
48
- setInterval(() => {
49
- runCron({ pg, func, name });
50
- }, intervalMs);
51
- }, waitMs);
52
- }
1
+ import config from '../../../../config.js';
2
+
3
+ import logger from '../../logger/getLogger.js';
4
+ import pgClients from '../../pg/pgClients.js';
5
+
6
+ import cronList from '../cronList.js';
7
+ import runCron from './runCron.js';
8
+ import interval2ms from './interval2ms.js';
9
+
10
+ /**
11
+ * interval:
12
+ * - 02:54 - every day
13
+ * - 2:03 - every day
14
+ * - *1:43 - 2 times a day
15
+ * - *12:03 - 2 times a day
16
+ * - **:54 - every hour
17
+ * - **:*3 - every 10 minutes
18
+ * - 60 - every minute
19
+ * - 10 * 60 - every 10 minutes
20
+ */
21
+
22
+ export default async function addCron(func, interval, pg = pgClients.client) {
23
+ const { time = {}, disabled = [] } = config.cron || {};
24
+
25
+ const name = func.name || func.toString().split('/').at(-1).split('\'')[0];
26
+
27
+ // if (!config.isServer) return;
28
+
29
+ if (disabled.includes(name)) {
30
+ logger.file('cron', { name, message: 'cron disabled' });
31
+ return;
32
+ }
33
+
34
+ cronList[name] = func;
35
+
36
+ const userInterval = time[name] || interval;
37
+ const [waitMs, intervalMs] = interval2ms[typeof interval](userInterval);
38
+
39
+ if (intervalMs < 1000) {
40
+ logger.file('cron', { name, error: `interval ${interval} too small` });
41
+ return;
42
+ }
43
+
44
+ // setTimeout to w8 for the time to start
45
+ setTimeout(() => {
46
+ runCron({ pg, func, name });
47
+ // interval
48
+ setInterval(() => {
49
+ runCron({ pg, func, name });
50
+ }, intervalMs);
51
+ }, waitMs);
52
+ }
@@ -1,14 +1,14 @@
1
- import config from '../../../../config.js';
2
- import getRedis from '../../redis/funcs/getRedis.js';
3
-
4
- const rclient = getRedis({ db: 0 });
5
-
6
- export default async function getOpt(token, uid = 0) {
7
- if (!config.redis) return null;
8
-
9
- const key = `opt:${uid}:${token}`;
10
- // console.log(key);
11
- const data = await rclient.get(key);
12
- if (!data) return null;
13
- return JSON.parse(data);
14
- }
1
+ import config from '../../../../config.js';
2
+ import getRedis from '../../redis/funcs/getRedis.js';
3
+
4
+ const rclient = getRedis({ db: 0 });
5
+
6
+ export default async function getOpt(token, uid = 0) {
7
+ if (!config.redis) return null;
8
+
9
+ const key = `opt:${uid}:${token}`;
10
+ // console.log(key);
11
+ const data = await rclient.get(key);
12
+ if (!data) return null;
13
+ return JSON.parse(data);
14
+ }
@@ -1,11 +1,11 @@
1
- import path from 'node:path';
2
-
3
- import config from '../../../../../config.js';
4
-
5
- export default function getFolder(req, type = 'server') {
6
- if (!['server', 'local'].includes(type)) throw new Error('params type is invalid');
7
- const types = { local: req.root || config.root, server: req.mapServerRoot || config.mapServerRoot };
8
- const dbname = req.pg?.options?.database || req.pg?.database || config.pg?.database; // request / config params / default config params
9
- const filepath = path.posix.join(types[type] || `/data/local/${dbname || ''}`, req.folder || config.folder || '');
10
- return filepath;
11
- }
1
+ import path from 'node:path';
2
+
3
+ import config from '../../../../../config.js';
4
+
5
+ export default function getFolder(req, type = 'server') {
6
+ if (!['server', 'local'].includes(type)) throw new Error('params type is invalid');
7
+ const types = { local: req.root || config.root, server: req.mapServerRoot || config.mapServerRoot };
8
+ const dbname = req.pg?.options?.database || req.pg?.database || config.pg?.database; // request / config params / default config params
9
+ const filepath = path.posix.join(types[type] || `/data/local/${dbname || ''}`, req.folder || config.folder || '');
10
+ return filepath;
11
+ }
@@ -1,19 +1,19 @@
1
- import applyHookSync from '../hook/funcs/applyHookSync.js';
2
-
3
- function errorStatus(error) {
4
- const hook = applyHookSync('errorStatus', error);
5
- if (hook) return hook;
6
-
7
- if (error.routine === 'exec_stmt_raise' && error.file === 'pl_exec.c') {
8
- return 601;
9
- }
10
- if (error.routine === 'ExecConstraints') {
11
- return 602;
12
- }
13
- if (error.type === 'DatabaseError') {
14
- return 600;
15
- }
16
-
17
- return 500;
18
- }
19
- export default errorStatus;
1
+ import applyHookSync from '../hook/funcs/applyHookSync.js';
2
+
3
+ function errorStatus(error) {
4
+ const hook = applyHookSync('errorStatus', error);
5
+ if (hook) return hook;
6
+
7
+ if (error.routine === 'exec_stmt_raise' && error.file === 'pl_exec.c') {
8
+ return 601;
9
+ }
10
+ if (error.routine === 'ExecConstraints') {
11
+ return 602;
12
+ }
13
+ if (error.type === 'DatabaseError') {
14
+ return 600;
15
+ }
16
+
17
+ return 500;
18
+ }
19
+ export default errorStatus;
@@ -1,8 +1,8 @@
1
- import redisClients from './funcs/redisClients.js';
2
- import getRedis from './funcs/getRedis.js';
3
-
4
- if (!redisClients[0]) {
5
- getRedis({ db: 0 });
6
- }
7
-
8
- export default redisClients[0];
1
+ import redisClients from './funcs/redisClients.js';
2
+ import getRedis from './funcs/getRedis.js';
3
+
4
+ if (!redisClients[0]) {
5
+ getRedis({ db: 0 });
6
+ }
7
+
8
+ export default redisClients[0];
@@ -1,3 +1,3 @@
1
- const redisClients = {};
2
-
3
- export default redisClients;
1
+ const redisClients = {};
2
+
3
+ export default redisClients;
@@ -1,6 +1,11 @@
1
- /* eslint-disable no-console */
1
+ import path from 'node:path';
2
2
 
3
- import Database from 'better-sqlite3';
3
+ const { name: execName } = path.parse(process.argv0);
4
+
5
+ // import Database from 'better-sqlite3'; // error with bun
6
+ const { default: Database } = execName === 'bun'
7
+ ? { default: (await import('bun:sqlite')).Database }
8
+ : await import('better-sqlite3');
4
9
 
5
10
  import config from '../../../../config.js';
6
11
  import sqliteClients from '../sqliteClients.js';
@@ -25,7 +30,7 @@ function getSqliteAsync({
25
30
  verbose: config.trace ? console.log : undefined,
26
31
  };
27
32
 
28
- sqliteClients.client = new Database(name || ':memory:', dbConfig);
33
+ sqliteClients.client = new Database(name || ':memory:', execName === 'bun' ? undefined : dbConfig);
29
34
  init(sqliteClients.client);
30
35
 
31
36
  return sqliteClients.client;
@@ -47,7 +47,7 @@ function init(client) {
47
47
  tlist,
48
48
  });
49
49
 
50
- console.log('db connected', client.name || ':memory:');
50
+ console.log('sqlite db connected', client.name || ':memory:');
51
51
  }
52
52
 
53
53
  export default init;
@@ -1,6 +1,11 @@
1
- /* eslint-disable no-console */
1
+ import path from 'node:path';
2
2
 
3
- import Database from 'better-sqlite3';
3
+ const { name: execName } = path.parse(process.argv0);
4
+
5
+ // import Database from 'better-sqlite3';
6
+ const { default: Database } = execName === 'bun'
7
+ ? { default: (await import('bun:sqlite')).Database }
8
+ : await import('better-sqlite3');
4
9
 
5
10
  import config from '../../../config.js';
6
11
  import init from './funcs/init.js';
@@ -8,7 +13,7 @@ import init from './funcs/init.js';
8
13
  const sqliteClients = {};
9
14
 
10
15
  if (config.sqlite) {
11
- const client = new Database(config.sqlite?.name || ':memory:', {
16
+ const client = new Database(config.sqlite?.name || ':memory:', execName === 'bun' ? undefined : {
12
17
  readonly: config.sqlite?.readonly || false,
13
18
  fileMustExist: config.sqlite?.fileMustExist || false,
14
19
  timeout: config.sqlite?.statement_timeout || 10000,
@@ -1,13 +1,13 @@
1
- async function getCustomQuery({
2
- pg, table, customFilter,
3
- }) {
4
- if (!customFilter) return null;
5
- const customFilterList = customFilter?.split(',')?.map((el) => el?.split('_').pop());
6
- const { property_json: customFilterSQL } = await pg.one(`select json_agg(json_build_object('id',property_id,'name',property_key,'query',property_text)
7
- ) as property_json from admin.properties where property_key is not null and property_entity='customQuery' and object_id=$1`, [table]);
8
- const data = customFilterSQL?.length ? customFilterSQL.filter((el) => customFilterList.includes(el.id)) || [] : [];
9
- const customQuery = data?.map((el) => el.query).join(' and ');
10
- return `${customQuery}`;
11
- }
12
-
13
- export default getCustomQuery;
1
+ async function getCustomQuery({
2
+ pg, table, customFilter,
3
+ }) {
4
+ if (!customFilter) return null;
5
+ const customFilterList = customFilter?.split(',')?.map((el) => el?.split('_').pop());
6
+ const { property_json: customFilterSQL } = await pg.one(`select json_agg(json_build_object('id',property_id,'name',property_key,'query',property_text)
7
+ ) as property_json from admin.properties where property_key is not null and property_entity='customQuery' and object_id=$1`, [table]);
8
+ const data = customFilterSQL?.length ? customFilterSQL.filter((el) => customFilterList.includes(el.id)) || [] : [];
9
+ const customQuery = data?.map((el) => el.query).join(' and ');
10
+ return `${customQuery}`;
11
+ }
12
+
13
+ export default getCustomQuery;
@@ -1,34 +1,34 @@
1
- function getTable(table) {
2
- const result = table?.toLowerCase()?.replace(/[\n\r]+/g, ' ')?.split(' from ')?.filter((el) => /^[a-z0-9_]+\.[a-z0-9_]+/.test(el))
3
- ?.map((el) => el.split(/[ )]/)[0]);
4
- return result;
5
- }
6
-
7
- /**
8
- * @param {Number} opt.json - (1|0) 1 - Результат - Object, 0 - String
9
- * @param {String} opt.query - запит до таблиці
10
- * @param {String} opt.hash - інформація з хешу по запиту
11
- */
12
- const tableSql = {};
13
- async function getTableSql({
14
- pg, body, table, fields,
15
- }) {
16
- if (tableSql[table]) return tableSql[table];
17
-
18
- const fieldList = fields.map((el) => el.name);
19
-
20
- const tableList = body?.sql?.map((el) => getTable(el.sql)).reduce((acc, el) => acc.concat(el), []).filter((el) => fieldList.includes(pg.pk[el]));
21
-
22
- if (!tableList) { tableSql[table] = []; return []; }
23
-
24
- const data = await Promise.all(tableList?.map(async (tableEl) => {
25
- const { fields: fieldsEl } = await pg.query(`select * from ${tableEl} limit 0`);
26
- return fieldsEl.map((el) => ({ name: el.name, table: tableEl, pk: pg.pk[tableEl] }));
27
- }));
28
-
29
- tableSql[table] = data.reduce((acc, el) => acc.concat(el), []);
30
-
31
- return tableSql[table];
32
- }
33
-
34
- export default getTableSql;
1
+ function getTable(table) {
2
+ const result = table?.toLowerCase()?.replace(/[\n\r]+/g, ' ')?.split(' from ')?.filter((el) => /^[a-z0-9_]+\.[a-z0-9_]+/.test(el))
3
+ ?.map((el) => el.split(/[ )]/)[0]);
4
+ return result;
5
+ }
6
+
7
+ /**
8
+ * @param {Number} opt.json - (1|0) 1 - Результат - Object, 0 - String
9
+ * @param {String} opt.query - запит до таблиці
10
+ * @param {String} opt.hash - інформація з хешу по запиту
11
+ */
12
+ const tableSql = {};
13
+ async function getTableSql({
14
+ pg, body, table, fields,
15
+ }) {
16
+ if (tableSql[table]) return tableSql[table];
17
+
18
+ const fieldList = fields.map((el) => el.name);
19
+
20
+ const tableList = body?.sql?.map((el) => getTable(el.sql)).reduce((acc, el) => acc.concat(el), []).filter((el) => fieldList.includes(pg.pk[el]));
21
+
22
+ if (!tableList) { tableSql[table] = []; return []; }
23
+
24
+ const data = await Promise.all(tableList?.map(async (tableEl) => {
25
+ const { fields: fieldsEl } = await pg.query(`select * from ${tableEl} limit 0`);
26
+ return fieldsEl.map((el) => ({ name: el.name, table: tableEl, pk: pg.pk[tableEl] }));
27
+ }));
28
+
29
+ tableSql[table] = data.reduce((acc, el) => acc.concat(el), []);
30
+
31
+ return tableSql[table];
32
+ }
33
+
34
+ export default getTableSql;
@@ -1,19 +1,19 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
-
4
- import config from '../../../../config.js';
5
-
6
- const loadTemplate = {};
7
-
8
- export default async function getTemplateDir(type) {
9
- if (!type) return null;
10
-
11
- const cwd = process.cwd();
12
- const typeDir = path.join(cwd, (config.templateDir || 'server/templates'), type);
13
-
14
- if (!loadTemplate[type]) {
15
- const typeList = fs.existsSync(typeDir) ? fs.readdirSync(typeDir) : [];
16
- loadTemplate[type] = typeList;
17
- }
18
- return loadTemplate[type];
19
- }
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+
4
+ import config from '../../../../config.js';
5
+
6
+ const loadTemplate = {};
7
+
8
+ export default async function getTemplateDir(type) {
9
+ if (!type) return null;
10
+
11
+ const cwd = process.cwd();
12
+ const typeDir = path.join(cwd, (config.templateDir || 'server/templates'), type);
13
+
14
+ if (!loadTemplate[type]) {
15
+ const typeList = fs.existsSync(typeDir) ? fs.readdirSync(typeDir) : [];
16
+ loadTemplate[type] = typeList;
17
+ }
18
+ return loadTemplate[type];
19
+ }
@@ -1,82 +1,82 @@
1
- import getSelect from './getSelect.js';
2
-
3
- import getFilterSQL from './getFilterSQL/index.js';
4
- import getTemplate from './getTemplate.js';
5
- import pgClients from '../../pg/pgClients.js';
6
- import config from '../../../../config.js';
7
- import getSelectVal from './metaFormat/getSelectVal.js';
8
-
9
- export default async function gisIRColumn({
10
- pg = pgClients.client, layer, column, sql, query = '1=1', filter, state, search, custom,
11
- }) {
12
- const time = Date.now();
13
-
14
- const sel = await getSelect(query.cls || column, pg);
15
-
16
- const body = await getTemplate('table', layer);
17
- const fData = await getFilterSQL({
18
- table: layer,
19
- filter,
20
- state,
21
- search,
22
- custom,
23
- });
24
-
25
- const { tlist } = await pg.one(`select array_agg((select nspname from pg_namespace where oid=relnamespace)||'.'||relname) tlist from pg_class
26
- where relkind in ('r','v','m')`);
27
-
28
- const tableName = body?.table || layer;
29
- if (!tlist.includes(tableName)) return { error: `table not found: ${tableName}`, status: 400 };
30
-
31
- // eslint-disable-next-line max-len
32
- const { fields } = await pg.query(`select * from (${fData?.optimizedSQL || `select * from ${tableName}`})q limit 0`);
33
-
34
- const col = fields.find((el) => el.name === column);
35
-
36
- if (!col) return { status: 404, message: 'not found' };
37
- const colField = pg.pgType[col.dataTypeID]?.includes('[]') ? `unnest(${column})` : column;
38
-
39
- const q = `select ${colField} as id, count(*)::int from (
40
- ${fData?.optimizedSQL || `select * from ${tableName} where ${body?.query || 'true'}`}
41
- )t group by ${colField} order by count desc limit 15`;
42
-
43
- if (sql) return q;
44
-
45
- if (!body?.columns?.length) {
46
- const { rows } = await pg.query(q);
47
- if (sel?.arr?.length) {
48
- rows.forEach((el) => {
49
- const data = sel?.find((item) => item.id?.toString() === el.id?.toString());
50
- Object.assign(el, data || {});
51
- });
52
- }
53
- return {
54
- count: rows?.reduce((acc, el) => acc + el.count, 0),
55
- sql: config.local ? q : undefined,
56
- rows,
57
- };
58
- }
59
-
60
- const { rows } = await pg.query(q);
61
- const cls = query.cls || body?.columns?.find((el) => el.name === column)?.data || col.data || col.option;
62
- const select = await getSelectVal({
63
- pg, name: cls, values: rows.map((el) => el.id), ar: 1,
64
- });
65
- rows.forEach((el) => {
66
- if (Array.isArray(select)) {
67
- Object.assign(el, select.find((item) => item.id?.toString() === el.id?.toString()) || {});
68
- }
69
- else if (typeof select?.[el.id] === 'string') {
70
- Object.assign(el, { text: select?.[el.id] });
71
- }
72
- else {
73
- Object.assign(el, select?.[el.id] || {});
74
- }
75
- });
76
- return {
77
- time: Date.now() - time,
78
- count: rows.reduce((acc, el) => acc + el.count, 0),
79
- sql: config.local ? q : undefined,
80
- rows,
81
- };
82
- }
1
+ import getSelect from './getSelect.js';
2
+
3
+ import getFilterSQL from './getFilterSQL/index.js';
4
+ import getTemplate from './getTemplate.js';
5
+ import pgClients from '../../pg/pgClients.js';
6
+ import config from '../../../../config.js';
7
+ import getSelectVal from './metaFormat/getSelectVal.js';
8
+
9
+ export default async function gisIRColumn({
10
+ pg = pgClients.client, layer, column, sql, query = '1=1', filter, state, search, custom,
11
+ }) {
12
+ const time = Date.now();
13
+
14
+ const sel = await getSelect(query.cls || column, pg);
15
+
16
+ const body = await getTemplate('table', layer);
17
+ const fData = await getFilterSQL({
18
+ table: layer,
19
+ filter,
20
+ state,
21
+ search,
22
+ custom,
23
+ });
24
+
25
+ const { tlist } = await pg.one(`select array_agg((select nspname from pg_namespace where oid=relnamespace)||'.'||relname) tlist from pg_class
26
+ where relkind in ('r','v','m')`);
27
+
28
+ const tableName = body?.table || layer;
29
+ if (!tlist.includes(tableName)) return { error: `table not found: ${tableName}`, status: 400 };
30
+
31
+ // eslint-disable-next-line max-len
32
+ const { fields } = await pg.query(`select * from (${fData?.optimizedSQL || `select * from ${tableName}`})q limit 0`);
33
+
34
+ const col = fields.find((el) => el.name === column);
35
+
36
+ if (!col) return { status: 404, message: 'not found' };
37
+ const colField = pg.pgType[col.dataTypeID]?.includes('[]') ? `unnest(${column})` : column;
38
+
39
+ const q = `select ${colField} as id, count(*)::int from (
40
+ ${fData?.optimizedSQL || `select * from ${tableName} where ${body?.query || 'true'}`}
41
+ )t group by ${colField} order by count desc limit 15`;
42
+
43
+ if (sql) return q;
44
+
45
+ if (!body?.columns?.length) {
46
+ const { rows } = await pg.query(q);
47
+ if (sel?.arr?.length) {
48
+ rows.forEach((el) => {
49
+ const data = sel?.find((item) => item.id?.toString() === el.id?.toString());
50
+ Object.assign(el, data || {});
51
+ });
52
+ }
53
+ return {
54
+ count: rows?.reduce((acc, el) => acc + el.count, 0),
55
+ sql: config.local ? q : undefined,
56
+ rows,
57
+ };
58
+ }
59
+
60
+ const { rows } = await pg.query(q);
61
+ const cls = query.cls || body?.columns?.find((el) => el.name === column)?.data || col.data || col.option;
62
+ const select = await getSelectVal({
63
+ pg, name: cls, values: rows.map((el) => el.id), ar: 1,
64
+ });
65
+ rows.forEach((el) => {
66
+ if (Array.isArray(select)) {
67
+ Object.assign(el, select.find((item) => item.id?.toString() === el.id?.toString()) || {});
68
+ }
69
+ else if (typeof select?.[el.id] === 'string') {
70
+ Object.assign(el, { text: select?.[el.id] });
71
+ }
72
+ else {
73
+ Object.assign(el, select?.[el.id] || {});
74
+ }
75
+ });
76
+ return {
77
+ time: Date.now() - time,
78
+ count: rows.reduce((acc, el) => acc + el.count, 0),
79
+ sql: config.local ? q : undefined,
80
+ rows,
81
+ };
82
+ }
@@ -1 +1 @@
1
- export default {};
1
+ export default {};
@@ -1 +1 @@
1
- export default {};
1
+ export default {};
@@ -1 +1 @@
1
- export default [];
1
+ export default [];
@@ -37,7 +37,7 @@ export default async function getForm({
37
37
 
38
38
  const form = tokenData?.form
39
39
  || hookData?.form
40
- || await getTemplate('table', table).then(el => el.form) || {};
40
+ || await getTemplate('table', table).then(el => el?.form) || {};
41
41
 
42
42
  if (!form) {
43
43
  return reply.status(404).send('form not found');
@@ -1,74 +1,74 @@
1
- import {
2
- getMeta, metaFormat, getTemplates, getTemplate, handlebars,
3
- } from '../../../../utils.js';
4
-
5
- function sequence(tables, data, fn) {
6
- return tables.reduce((promise, table) => promise.then(() => fn({
7
- ...data, tableName: table.replace('.json', ''),
8
- })), Promise.resolve());
9
- }
10
-
11
- async function getData({
12
- pg, tableName, query = {}, maxLimit, res,
13
- }) {
14
- const loadTable = await getTemplate('table', tableName);
15
-
16
- if (!loadTable) { return { message: 'not found', status: 404 }; }
17
-
18
- const {
19
- table, columns, meta,
20
- } = loadTable;
21
-
22
- const { pk } = await getMeta(table);
23
-
24
- const cols = columns.map((el) => el.name || el).join(',');
25
- const [orderColumn, orderDir] = (query.order || loadTable.order || '').split('-');
26
- const order = cols.includes(orderColumn) && orderColumn?.length ? `order by ${orderColumn} ${query.desc || orderDir === 'desc' ? 'desc' : ''}` : '';
27
-
28
- const limit = Math.max(maxLimit - res.rows.length, 0);
29
- // Math.max(query.offset - res.rows.length,0)
30
- const offset = query.page && query.page > 0 ? ` offset ${(query.page - 1) * limit}` : '';
31
-
32
- const search1 = meta?.search && query.key ? `(${meta?.search.concat(meta?.title ? `,${meta?.title}` : '').split(',').map(el => `${el} ilike '%${query.key}%'`).join(' or ')})` : 'false';
33
-
34
- const where = [!pk ? 'false' : 'true', loadTable.query, search1].filter((el) => el);
35
- const q = `select ${[`"${pk}" as id`, meta?.title ? `${meta.title} as title` : ''].filter((el) => el).join(',')} from ${table} t where ${where.join(' and ') || 'true'} ${order} ${offset} limit ${limit}`;
36
- if (query.sql) {
37
- res.sql.push(q);
38
- return null;
39
- }
40
-
41
- const { rows } = await pg.query(q);
42
-
43
- const total = await pg.queryCache(`select count(*) from ${table} t where ${where.join(' and ') || 'true'}`).then((el) => el?.rows[0]?.count) || 0;
44
-
45
- await metaFormat({ rows, table: tableName });
46
- res.total += +total;
47
- rows.forEach((row) => {
48
- const href = meta?.href ? handlebars.compile(meta.href)({ ...row, [pk]: row.id }) : undefined;
49
- res.rows.push({
50
- ...row, register: tableName, register_title: loadTable.ua, href,
51
- });
52
- });
53
- return null;
54
- }
55
-
56
- export default async function search({
57
- pg, funcs, query = {},
58
- }) {
59
- const time = Date.now();
60
-
61
- const tables = query.table ? [query.table] : await getTemplates('table');
62
- const res = { rows: [], sql: [], total: 0 };
63
-
64
- const maxLimit = Math.min(100, query.limit || '16');
65
- await sequence(tables, {
66
- pg, funcs, query, maxLimit, res,
67
- }, getData);
68
-
69
- if (query.sql) return res.sql.join(';\n');
70
-
71
- return {
72
- time: Date.now() - time, total: res.total, count: res.rows.length, rows: res.rows,
73
- };
74
- }
1
+ import {
2
+ getMeta, metaFormat, getTemplates, getTemplate, handlebars,
3
+ } from '../../../../utils.js';
4
+
5
+ function sequence(tables, data, fn) {
6
+ return tables.reduce((promise, table) => promise.then(() => fn({
7
+ ...data, tableName: table.replace('.json', ''),
8
+ })), Promise.resolve());
9
+ }
10
+
11
+ async function getData({
12
+ pg, tableName, query = {}, maxLimit, res,
13
+ }) {
14
+ const loadTable = await getTemplate('table', tableName);
15
+
16
+ if (!loadTable) { return { message: 'not found', status: 404 }; }
17
+
18
+ const {
19
+ table, columns, meta,
20
+ } = loadTable;
21
+
22
+ const { pk } = await getMeta(table);
23
+
24
+ const cols = columns.map((el) => el.name || el).join(',');
25
+ const [orderColumn, orderDir] = (query.order || loadTable.order || '').split('-');
26
+ const order = cols.includes(orderColumn) && orderColumn?.length ? `order by ${orderColumn} ${query.desc || orderDir === 'desc' ? 'desc' : ''}` : '';
27
+
28
+ const limit = Math.max(maxLimit - res.rows.length, 0);
29
+ // Math.max(query.offset - res.rows.length,0)
30
+ const offset = query.page && query.page > 0 ? ` offset ${(query.page - 1) * limit}` : '';
31
+
32
+ const search1 = meta?.search && query.key ? `(${meta?.search.concat(meta?.title ? `,${meta?.title}` : '').split(',').map(el => `${el} ilike '%${query.key}%'`).join(' or ')})` : 'false';
33
+
34
+ const where = [!pk ? 'false' : 'true', loadTable.query, search1].filter((el) => el);
35
+ const q = `select ${[`"${pk}" as id`, meta?.title ? `${meta.title} as title` : ''].filter((el) => el).join(',')} from ${table} t where ${where.join(' and ') || 'true'} ${order} ${offset} limit ${limit}`;
36
+ if (query.sql) {
37
+ res.sql.push(q);
38
+ return null;
39
+ }
40
+
41
+ const { rows } = await pg.query(q);
42
+
43
+ const total = await pg.queryCache(`select count(*) from ${table} t where ${where.join(' and ') || 'true'}`).then((el) => el?.rows[0]?.count) || 0;
44
+
45
+ await metaFormat({ rows, table: tableName });
46
+ res.total += +total;
47
+ rows.forEach((row) => {
48
+ const href = meta?.href ? handlebars.compile(meta.href)({ ...row, [pk]: row.id }) : undefined;
49
+ res.rows.push({
50
+ ...row, register: tableName, register_title: loadTable.ua, href,
51
+ });
52
+ });
53
+ return null;
54
+ }
55
+
56
+ export default async function search({
57
+ pg, funcs, query = {},
58
+ }) {
59
+ const time = Date.now();
60
+
61
+ const tables = query.table ? [query.table] : await getTemplates('table');
62
+ const res = { rows: [], sql: [], total: 0 };
63
+
64
+ const maxLimit = Math.min(100, query.limit || '16');
65
+ await sequence(tables, {
66
+ pg, funcs, query, maxLimit, res,
67
+ }, getData);
68
+
69
+ if (query.sql) return res.sql.join(';\n');
70
+
71
+ return {
72
+ time: Date.now() - time, total: res.total, count: res.rows.length, rows: res.rows,
73
+ };
74
+ }
@@ -1,89 +1,99 @@
1
- import config from '../../../../config.js';
2
- import isFileExists from '../../../plugins/file/isFileExists.js';
3
- import logChanges from '../../../plugins/crud/funcs/utils/logChanges.js';
4
- import pgClients from '../../../plugins/pg/pgClients.js';
5
-
6
- const isAdmin = (req) => process.env.NODE_ENV === 'admin'
7
- || config.admin
8
- || req?.hostname?.split?.(':')?.shift?.() === config.adminDomain
9
- || req?.hostname?.startsWith?.('admin');
10
-
11
- async function checkAccess(pg, objectid, id) {
12
- const { uid, filepath } = await pg.query('select uid, file_path as filepath from crm.files where entity_id=$1 and file_id=$2', [objectid, id])
13
- .then(el => el.rows?.[0] || {});
14
- return { uid, exists: filepath ? await isFileExists(filepath) : null };
15
- }
16
-
17
- /**
18
- * Дістає CRM дані для vue хешує ідентифікатори, підтягує селекти
19
- *
20
- * @method DELETE
21
- * @summary CRM дані для обраного віджета.
22
- * @priority 2
23
- * @tag table
24
- * @type api
25
- * @requires setTokenById
26
- * @requires getSelect
27
- * @param {String} id Ідентифікатор для хешування
28
- * @param {Any} sql Використовується для повернення sql запиту
29
- * @param {String} type Тип для хешування даних
30
- * @errors 400, 500
31
- * @returns {Number} status Номер помилки
32
- * @returns {String|Object} error Опис помилки
33
- * @returns {String|Object} message Повідомлення про успішне виконання або об'єкт з параметрами
34
- */
35
-
36
- export default async function widgetDel(req, reply) {
37
- const {
38
- pg = pgClients.client, params = {}, user = {},
39
- } = req;
40
-
41
- if (!user?.uid) {
42
- return reply.status(401).send('access restricted: user not authorized');
43
- }
44
-
45
- const { type, objectid, id } = params;
46
-
47
- if (!objectid) {
48
- return reply.status(400).send('not enough params: id');
49
- }
50
-
51
- // force delete db entry if file not exists
52
- const { exists, uid } = ['file', 'gallery'].includes(type) ? await checkAccess(pg, objectid, id) : {};
53
-
54
- if (exists && !isAdmin(req) && uid && user?.uid !== uid) {
55
- return reply.status(403).send('access restricted: file exists, not an author');
56
- }
57
-
58
- const sqls = {
59
- comment: `delete from crm.communications where entity_id=$1 and ${isAdmin(req) ? '$2=$2' : 'uid=$2'} and communication_id=$3`,
60
- checklist: `delete from crm.checklists where entity_id=$1 and ${isAdmin(req) ? '$2=$2' : 'uid=$2'} and checklist_id=$3`,
61
- file: `update crm.files set file_status=3 where entity_id=$1 and ${!exists || isAdmin(req) ? '$2=$2' : 'uid=$2'} and file_id=$3 returning uploaded_name`,
62
- gallery: `update crm.files set file_status=3 where entity_id=$1 and ${!exists || isAdmin(req) ? '$2=$2' : 'uid=$2'} and file_id=$3 returning uploaded_name`,
63
- };
64
-
65
- const sql = sqls[type];
66
- const table = {
67
- comment: 'crm.communications',
68
- checklist: 'crm.checklists',
69
- file: 'crm.files',
70
- gallery: 'crm.files',
71
- }[type];
72
-
73
- if (!sql) {
74
- return reply.status(400).send('invalid widget type');
75
- }
76
-
77
- const { rows = [] } = await pg.query(sql, [objectid, user.uid, id]);
78
-
79
- await logChanges({
80
- pg,
81
- table,
82
- id,
83
- data: rows[0],
84
- uid: user?.uid,
85
- type: 'DELETE',
86
- });
87
-
88
- return reply.status(200).send({ data: { id }, user: { uid: user.uid, name: user.user_name } });
89
- }
1
+ import config from '../../../../config.js';
2
+ import isFileExists from '../../../plugins/file/isFileExists.js';
3
+ import logChanges from '../../../plugins/crud/funcs/utils/logChanges.js';
4
+ import pgClients from '../../../plugins/pg/pgClients.js';
5
+
6
+ const isAdmin = (req) => process.env.NODE_ENV === 'admin'
7
+ || config.admin
8
+ || req?.hostname?.split?.(':')?.shift?.() === config.adminDomain
9
+ || req?.hostname?.startsWith?.('admin');
10
+
11
+ async function checkAccess(pg, objectid, id) {
12
+ const { uid, filepath } = await pg.query('select uid, file_path as filepath from crm.files where entity_id=$1 and file_id=$2', [objectid, id])
13
+ .then(el => el.rows?.[0] || {});
14
+ return { uid, exists: filepath ? await isFileExists(filepath) : null };
15
+ }
16
+
17
+ /**
18
+ * Дістає CRM дані для vue хешує ідентифікатори, підтягує селекти
19
+ *
20
+ * @method DELETE
21
+ * @summary CRM дані для обраного віджета.
22
+ * @priority 2
23
+ * @tag table
24
+ * @type api
25
+ * @requires setTokenById
26
+ * @requires getSelect
27
+ * @param {String} id Ідентифікатор для хешування
28
+ * @param {Any} sql Використовується для повернення sql запиту
29
+ * @param {String} type Тип для хешування даних
30
+ * @errors 400, 500
31
+ * @returns {Number} status Номер помилки
32
+ * @returns {String|Object} error Опис помилки
33
+ * @returns {String|Object} message Повідомлення про успішне виконання або об'єкт з параметрами
34
+ */
35
+
36
+ export default async function widgetDel(req, reply) {
37
+ const {
38
+ pg = pgClients.client, params = {}, user = {},
39
+ } = req;
40
+
41
+ if (!user?.uid) {
42
+ return reply.status(401).send('access restricted: user not authorized');
43
+ }
44
+
45
+ const { type, objectid, id } = params;
46
+
47
+ if (!objectid) {
48
+ return reply.status(400).send('not enough params: object id');
49
+ }
50
+
51
+ if (!id && type !== 'reaction') {
52
+ return reply.status(400).send('not enough params: id');
53
+ }
54
+
55
+ // force delete db entry if file not exists
56
+ const { exists, uid } = ['file', 'gallery'].includes(type) ? await checkAccess(pg, objectid, id) : {};
57
+
58
+ if (exists && !isAdmin(req) && uid && user?.uid !== uid) {
59
+ return reply.status(403).send('access restricted: file exists, not an author');
60
+ }
61
+
62
+ const sqls = {
63
+ comment: `delete from crm.communications where entity_id=$1 and ${isAdmin(req) ? '$2=$2' : 'uid=$2'} and communication_id=$3`,
64
+ checklist: `delete from crm.checklists where entity_id=$1 and ${isAdmin(req) ? '$2=$2' : 'uid=$2'} and checklist_id=$3`,
65
+ file: `update crm.files set file_status=3 where entity_id=$1 and ${!exists || isAdmin(req) ? '$2=$2' : 'uid=$2'} and file_id=$3 returning uploaded_name`,
66
+ gallery: `update crm.files set file_status=3 where entity_id=$1 and ${!exists || isAdmin(req) ? '$2=$2' : 'uid=$2'} and file_id=$3 returning uploaded_name`,
67
+ reaction: `delete from crm.reactions where entity_id=$1 and ${isAdmin(req) ? '$2=$2' : 'created_by=$2'} and $3=$3 returning reaction_type`,
68
+ };
69
+
70
+ const sql = sqls[type];
71
+ const table = {
72
+ comment: 'crm.communications',
73
+ checklist: 'crm.checklists',
74
+ file: 'crm.files',
75
+ gallery: 'crm.files',
76
+ reaction: 'crm.reactions',
77
+ }[type];
78
+
79
+ if (!sql) {
80
+ return reply.status(400).send('invalid widget type');
81
+ }
82
+
83
+ const { rows = [] } = await pg.query(sql, [objectid, user.uid, id || '']);
84
+
85
+ if (type === 'reaction') {
86
+ console.log('231131');
87
+ }
88
+
89
+ await logChanges({
90
+ pg,
91
+ table,
92
+ id: type === 'reaction' ? objectid : id,
93
+ data: rows[0],
94
+ uid: user?.uid,
95
+ type: 'DELETE',
96
+ });
97
+
98
+ return reply.status(200).send({ data: { id }, user: { uid: user.uid, name: user.user_name } });
99
+ }
@@ -87,7 +87,7 @@ export default async function widgetGet({
87
87
  where entity_id=$1 and file_status<>3 and ext = any($2) order by cdate desc`
88
88
  : `SELECT file_id, entity_id, entity_type, file_path, uploaded_name, ext, size, c.uid, c.cdate, file_type, ismain,
89
89
  isverified, uid as author, file_status FROM crm.files c where entity_id=$1 and file_status<>3 and ext = any($2) order by cdate desc`,
90
-
90
+ reaction: 'SELECT count(*), reaction_type FROM crm.reactions c where entity_id=$1 group by reaction_type',
91
91
  };
92
92
 
93
93
  const q = sqls[params.type];
@@ -11,23 +11,25 @@ const tableList = {
11
11
  gallery: 'crm.files',
12
12
  file: 'crm.files',
13
13
  checklist: 'crm.checklists',
14
+ reaction: 'crm.reactions',
14
15
  };
15
16
  const pkList = {
16
17
  comment: 'communication_id',
17
18
  checklist: 'checklist_id',
18
19
  file: 'file_id',
19
20
  gallery: 'file_id',
21
+ reaction: 'reaction_id',
20
22
  };
21
23
 
22
24
  const galleryExtList = ['png', 'svg', 'jpg', 'jpeg', 'gif', 'mp4', 'mov', 'avi'];
23
25
 
24
26
  export default async function widgetSet(req, reply) {
25
27
  const {
26
- pg, params = {}, session = {}, headers = {}, body = {}, user = {},
28
+ pg, params = {}, headers = {}, body = {}, user = {},
27
29
  } = req;
28
30
  const { type, id, objectid } = params;
29
31
 
30
- if (!['comment', 'checklist', 'file', 'gallery'].includes(type)) {
32
+ if (!['comment', 'checklist', 'file', 'gallery', 'reaction'].includes(type)) {
31
33
  return reply.status(400).send('param type not valid');
32
34
  }
33
35
 
@@ -1,13 +1,13 @@
1
- import pgClients from '../../../plugins/pg/pgClients.js';
2
-
3
- export default async function onWidgetSet({
4
- pg = pgClients.client, id, objectid, type, payload = {},
5
- }) {
6
- if (!id || !objectid || type !== 'gallery') {
7
- return null;
8
- }
9
- if (payload?.ismain) {
10
- await pg.query('update crm.files set ismain=false where entity_id=$1 and file_id<>$2', [objectid, id]);
11
- }
12
- return null;
13
- }
1
+ import pgClients from '../../../plugins/pg/pgClients.js';
2
+
3
+ export default async function onWidgetSet({
4
+ pg = pgClients.client, id, objectid, type, payload = {},
5
+ }) {
6
+ if (!id || !objectid || type !== 'gallery') {
7
+ return null;
8
+ }
9
+ if (payload?.ismain) {
10
+ await pg.query('update crm.files set ismain=false where entity_id=$1 and file_id<>$2', [objectid, id]);
11
+ }
12
+ return null;
13
+ }
@@ -1,38 +1,38 @@
1
- import addHook from '../../plugins/hook/funcs/addHook.js';
2
-
3
- import widgetDel from './controllers/widget.del.js';
4
- import widgetSet from './controllers/widget.set.js';
5
- import widgetGet from './controllers/widget.get.js';
6
- import fileEdit from './controllers/file.edit.js';
7
-
8
- import onWidgetSet from './hook/onWidgetSet.js';
9
-
10
- const tableSchema = {
11
- params: {
12
- type: 'object',
13
- properties: {
14
- // type: { type: 'string', pattern: '^([\\d\\w]+)$' },
15
- objectid: { type: 'string', pattern: '^([\\d\\w]+)$' },
16
- id: { type: 'string', pattern: '^([\\d\\w]+)$' },
17
- },
18
- },
19
- querystring: {
20
- type: 'object',
21
- properties: {
22
- debug: { type: 'string', pattern: '^(\\d+)$' },
23
- },
24
- },
25
- };
26
-
27
- addHook('onWidgetSet', onWidgetSet);
28
-
29
- const policy = ['site'];
30
- const params = { config: { policy }, schema: tableSchema };
31
-
32
- export default async function route(app, config = {}) {
33
- const { prefix = '/api' } = config;
34
- app.delete(`${prefix}/widget/:type/:objectid/:id`, params, widgetDel);
35
- app.post(`${prefix}/widget/:type/:objectid/:id?`, params, widgetSet);
36
- app.put(`${prefix}/file-edit/:id`, params, fileEdit);
37
- app.get(`${prefix}/widget/:type/:objectid`, { config: { policy: ['public'] }, schema: tableSchema }, widgetGet);
38
- }
1
+ import addHook from '../../plugins/hook/funcs/addHook.js';
2
+
3
+ import widgetDel from './controllers/widget.del.js';
4
+ import widgetSet from './controllers/widget.set.js';
5
+ import widgetGet from './controllers/widget.get.js';
6
+ import fileEdit from './controllers/file.edit.js';
7
+
8
+ import onWidgetSet from './hook/onWidgetSet.js';
9
+
10
+ const tableSchema = {
11
+ params: {
12
+ type: 'object',
13
+ properties: {
14
+ type: { type: 'string', enum: ['gallery', 'file', 'checklist', 'history', 'comment', 'reaction'] },
15
+ objectid: { type: 'string', pattern: '^([\\d\\w]+)$' },
16
+ id: { type: 'string', pattern: '^([\\d\\w]+)$' },
17
+ },
18
+ },
19
+ querystring: {
20
+ type: 'object',
21
+ properties: {
22
+ debug: { type: 'string', pattern: '^(\\d+)$' },
23
+ },
24
+ },
25
+ };
26
+
27
+ addHook('onWidgetSet', onWidgetSet);
28
+
29
+ const policy = ['site'];
30
+ const params = { config: { policy }, schema: tableSchema };
31
+
32
+ export default async function route(app, config = {}) {
33
+ const { prefix = '/api' } = config;
34
+ app.delete(`${prefix}/widget/:type/:objectid/:id`, params, widgetDel);
35
+ app.post(`${prefix}/widget/:type/:objectid/:id?`, params, widgetSet);
36
+ app.put(`${prefix}/file-edit/:id`, params, fileEdit);
37
+ app.get(`${prefix}/widget/:type/:objectid`, { config: { policy: ['public'] }, schema: tableSchema }, widgetGet);
38
+ }