@opengis/cms 0.0.13 → 0.0.15

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 (96) hide show
  1. package/dist/assets/ArticlesPage-BveM4q3g.js +11 -0
  2. package/dist/assets/CollectionsPage-D5td-UBm.js +1 -0
  3. package/dist/assets/ContentBlock.vue_vue_type_script_setup_true_lang-BwF6D-yB.js +30 -0
  4. package/dist/assets/CreateCollectionPage-Cu0RW5ui.js +76 -0
  5. package/dist/assets/Dashboard-faSjwmB8.js +11 -0
  6. package/dist/assets/EditCollectionPage-K5oPPzCd.js +1 -0
  7. package/dist/assets/MediaPage-BoW3aWgN.js +1 -0
  8. package/dist/assets/PermissionsPage-DGy5fha2.js +1 -0
  9. package/dist/assets/SingletonsPage-C1X2xkQE.js +1 -0
  10. package/dist/assets/UniversalTable.vue_vue_type_script_setup_true_lang-DUqfWJcy.js +6 -0
  11. package/dist/assets/calendar-hsWc4yH-.js +6 -0
  12. package/dist/assets/contentForm-DMVC4vho.js +1 -0
  13. package/dist/assets/database-BTxZQzYy.js +6 -0
  14. package/dist/assets/index-9GY17iSP.css +1 -0
  15. package/dist/assets/index-DYyZmLWO.js +2138 -0
  16. package/dist/assets/index-xsH4HHeE.js +6 -0
  17. package/dist/assets/logo-Cct5WB26.png +0 -0
  18. package/dist/assets/plus-D9etvrM2.js +6 -0
  19. package/dist/assets/save-C2B6th9J.js +11 -0
  20. package/dist/assets/search-BI-hqhq6.js +6 -0
  21. package/dist/assets/settings-DbyDiH2g.js +6 -0
  22. package/dist/assets/square-pen-61CkyXzK.js +6 -0
  23. package/dist/assets/trash-2-CJSl_r88.js +6 -0
  24. package/dist/assets/vue.-sixQ7xP-DwXf3zRn.js +1 -0
  25. package/dist/assets/x-BNquQe5y.js +6 -0
  26. package/dist/assets/x-circle-C3q70RMH.js +16 -0
  27. package/dist/images/logo.png +0 -0
  28. package/dist/index.html +30 -0
  29. package/package.json +38 -32
  30. package/server/app.js +32 -10
  31. package/server/index.js +3 -3
  32. package/server/migrations/site.sql +26 -8
  33. package/server/plugins/adminHook.js +78 -0
  34. package/server/plugins/hook.js +54 -78
  35. package/server/plugins/vite.js +13 -9
  36. package/server/routes/cms/controllers/deleteContent.js +60 -0
  37. package/server/routes/{site → cms}/controllers/deleteMedia.js +46 -46
  38. package/server/routes/{site → cms}/controllers/downloadMedia.js +48 -48
  39. package/server/routes/cms/controllers/getContent.js +96 -0
  40. package/server/routes/{site → cms}/controllers/getPermissions.js +15 -15
  41. package/server/routes/cms/controllers/insertContent.js +69 -0
  42. package/server/routes/{site → cms}/controllers/listMedia.js +72 -72
  43. package/server/routes/{site → cms}/controllers/metadataMedia.js +37 -37
  44. package/server/routes/{site → cms}/controllers/setPermissions.js +49 -49
  45. package/server/routes/cms/controllers/updateContent.js +112 -0
  46. package/server/routes/{site → cms}/controllers/uploadMedia.js +65 -65
  47. package/server/routes/cms/index.mjs +45 -0
  48. package/server/routes/contentType/controllers/cms.type.delete.js +22 -0
  49. package/server/routes/contentType/controllers/cms.type.get.js +22 -0
  50. package/server/routes/contentType/controllers/cms.type.list.js +25 -0
  51. package/server/routes/contentType/controllers/cms.type.post.js +22 -0
  52. package/server/routes/contentType/controllers/cms.type.put.js +24 -0
  53. package/server/routes/contentType/index.mjs +25 -0
  54. package/server/routes/contentType/utils/builderCache.js +58 -0
  55. package/server/routes/fileContent/data/deleteContent.js +34 -0
  56. package/server/routes/fileContent/data/deleteMedia.js +28 -0
  57. package/server/routes/fileContent/data/downloadMedia.js +41 -0
  58. package/server/routes/fileContent/data/getContent.js +32 -0
  59. package/server/routes/fileContent/data/insertContent.js +37 -0
  60. package/server/routes/fileContent/data/listMedia.js +47 -0
  61. package/server/routes/fileContent/data/metadataMedia.js +38 -0
  62. package/server/routes/fileContent/data/updateContent.js +40 -0
  63. package/server/routes/fileContent/data/uploadMedia.js +49 -0
  64. package/server/routes/fileContent/index.mjs +54 -0
  65. package/server/routes/fileContent/type/contentTypeList.js +7 -0
  66. package/server/routes/fileContent/type/createContentType.js +31 -0
  67. package/server/routes/fileContent/type/deleteContentType.js +29 -0
  68. package/server/routes/fileContent/type/getContentType.js +15 -0
  69. package/server/routes/fileContent/type/updateContentType.js +40 -0
  70. package/server/routes/fileContent/utils/astroBuilderCache.js +47 -0
  71. package/server/routes/fileContent/utils/contentDir.js +12 -0
  72. package/server/routes/fileContent/utils/contentTypeExists.js +15 -0
  73. package/server/routes/root.mjs +0 -7
  74. package/dist/cms.js +0 -6727
  75. package/dist/cms.umd.cjs +0 -19
  76. package/dist/style.css +0 -1
  77. package/server/routes/builder/controllers/cms.builder.delete.js +0 -21
  78. package/server/routes/builder/controllers/cms.builder.get.js +0 -17
  79. package/server/routes/builder/controllers/cms.builder.list.js +0 -16
  80. package/server/routes/builder/controllers/cms.builder.post.js +0 -21
  81. package/server/routes/builder/controllers/cms.builder.put.js +0 -23
  82. package/server/routes/builder/index.mjs +0 -22
  83. package/server/routes/manager/controllers/cms.manager.delete.js +0 -22
  84. package/server/routes/manager/controllers/cms.manager.get.js +0 -21
  85. package/server/routes/manager/controllers/cms.manager.list.js +0 -31
  86. package/server/routes/manager/controllers/cms.manager.post.js +0 -28
  87. package/server/routes/manager/controllers/cms.manager.put.js +0 -23
  88. package/server/routes/manager/index.mjs +0 -22
  89. package/server/routes/media/controllers/delete.js +0 -59
  90. package/server/routes/media/controllers/edit.js +0 -94
  91. package/server/routes/media/controllers/list.js +0 -74
  92. package/server/routes/media/controllers/metadata.js +0 -51
  93. package/server/routes/media/controllers/preview.js +0 -47
  94. package/server/routes/media/controllers/upload.js +0 -79
  95. package/server/routes/media/index.mjs +0 -16
  96. package/server/routes/site/index.mjs +0 -34
@@ -1,91 +1,67 @@
1
1
  import fp from 'fastify-plugin';
2
- import fs from 'fs';
3
- import config from '../config.js';
4
2
 
5
- // the use of fastify-plugin is required to be able
6
- // to export the decorators to the outer scope
3
+ import { config, pgClients } from '@opengis/fastify-table/utils.js';
7
4
 
8
- async function plugin(fastify) {
9
- fastify.decorate('config', config);
5
+ import builderCache from '../routes/contentType/utils/builderCache.js';
10
6
 
11
- // pre Request
12
- fastify.addHook('onRequest', async (req) => {
13
- req.funcs = fastify;
14
- const { user } = req.session?.passport || {};
15
- req.user = user;
16
- });
7
+ const matches = {
8
+ date: 'timestamp without time zone',
9
+ };
17
10
 
18
- // preSerialization
19
- fastify.addHook('preSerialization', async (req, reply, payload) => {
20
- if (req.url.includes('/suggest/') && !req.query.json) {
21
- return payload?.data;
22
- }
23
- /* if (payload.redirect) {
24
- return reply.redirect(payload.redirect);
25
- }*/
26
- if (reply.sent) {
27
- return null;
28
- }
29
- if (!payload) {
30
- return payload;
11
+ const defaultColumns = [
12
+ {
13
+ name: 'created_at',
14
+ type: 'date',
15
+ default: 'now()',
16
+ label: 'Created at',
17
+ required: true,
18
+ },
19
+ {
20
+ name: 'created_by',
21
+ type: 'text',
22
+ label: 'Created by'
23
+ },
24
+ {
25
+ name: 'updated_at',
26
+ type: 'date',
27
+ default: 'now()',
28
+ label: 'Updated at',
29
+ required: true,
30
+ },
31
+ {
32
+ name: 'updated_by',
33
+ type: 'text',
34
+ label: 'Updated by'
31
35
  }
36
+ ];
32
37
 
33
- if (['200', '400', '500', '403', '404'].includes(payload.status)) {
34
- reply.status(payload.status);
35
- }
36
- /* if (payload.headers) {
37
- reply.headers(payload.headers);
38
- } */
39
- if (payload.buffer) {
40
- return payload.buffer;
41
- }
42
- if (payload.file) {
43
- // const buffer = await readFile(payload.file);
44
- // return reply.send(buffer);
45
- const stream = fs.createReadStream(payload.file);
46
- return stream;
47
- // return reply.send(stream);
48
- }
38
+ function createTableSQL(name, slug = 'slug', columns = {}) {
39
+ const columnList = (Array.isArray(columns)
40
+ ? columns.filter(el => el.name)
41
+ : Object.entries(columns).map(el => ({ name: el[0], ...el[1] })));
49
42
 
50
- if (payload.message) {
51
- return payload.message;
52
- }
53
- return payload;
54
- });
43
+ defaultColumns.forEach(el => columnList.push(el));
55
44
 
56
- // preValidation
57
- fastify.addHook('preValidation', async (req) => {
58
- const parseRawBody = ['POST', 'PUT'].includes(req.method) && req.body && typeof req.body === 'string'
59
- && req.body.trim(/\r\n/g).startsWith('{')
60
- && req.body.trim(/\r\n/g).endsWith('}');
61
- if (parseRawBody) {
62
- try {
63
- req.body = JSON.parse(req.body || '{}');
64
- }
65
- catch (err) {
66
- // throw new Error('invalid body');
67
- // return { error: 'invalid body', status: 400 };
68
- }
69
- }
70
- });
71
-
72
- // allow upload file
73
- const kIsMultipart = Symbol.for('[FastifyMultipart.isMultipart]');
74
- fastify.addContentTypeParser('multipart', (request, _, done) => {
75
- request[kIsMultipart] = true;
76
- done(null);
77
- });
78
-
79
- // parse Body
80
- function contentParser(req, body, done) {
81
- const parseBody = decodeURIComponent(body.toString()).split('&').reduce((acc, el) => {
82
- const [key, val] = el.split('=');
83
- return { ...acc, [key]: val };
84
- }, {});
85
- done(null, parseBody);
86
- }
45
+ return `CREATE TABLE IF NOT EXISTS site.${name} ();
46
+ ALTER TABLE site.${name} ADD COLUMN IF NOT EXISTS ${name}_id text not null default next_id() PRIMARY KEY;
47
+ ALTER TABLE site.${name} ADD COLUMN IF NOT EXISTS ${slug} text;
48
+ ${columnList.map(el => `ALTER TABLE site.${name} ADD COLUMN IF NOT EXISTS ${el.name} ${matches[el.type] || 'text'};`).join('\n')}
49
+ ${columnList.filter(el => el.default).map(el => `ALTER TABLE site.${name} ALTER COLUMN ${el.name} SET DEFAULT ${el.default};`).join('\n')}
50
+ ${columnList.filter(el => Object.hasOwn(el, 'required')).map(el => `ALTER TABLE site.${name} ALTER COLUMN ${el.name} ${el.required ? 'SET' : 'DROP'} NOT NULL;`).join('\n')}
51
+ ${columnList.filter(el => el.label).map(el => `COMMENT ON COLUMN site.${name}.${el.name} IS '${el.label}';`).join('\n')}`;
52
+ }
87
53
 
88
- fastify.addContentTypeParser('application/x-www-form-urlencoded', { parseAs: 'buffer' }, contentParser);
54
+ async function plugin(app) {
55
+ if (config.pg && builderCache()?.length) {
56
+ app.addHook('onListen', async () => {
57
+ const files = builderCache().filter(el => el.type === 'collection' && el.provider === 'pg' && el.name);
58
+ const q = files.map(el => createTableSQL(el.name, el.slug, el.columns)).filter(el => el).join(';\n');
59
+ await pgClients.client.query(`create schema if not exists site;${q}`).catch(err => {
60
+ console.error('Builder deploy error:', err);
61
+ });
62
+ console.log('Builder deploy complete', files?.length);
63
+ });
64
+ }
89
65
  }
90
66
 
91
67
  export default fp(plugin);
@@ -1,11 +1,11 @@
1
- import fs from 'fs';
2
- import path, { dirname } from 'path';
1
+ import fs from 'node:fs';
2
+ import path, { dirname } from 'node:path';
3
3
  import { fileURLToPath } from 'url';
4
4
 
5
+ import { config } from '@opengis/fastify-table/utils.js';
6
+
5
7
  const dir = dirname(fileURLToPath(import.meta.url));
6
8
  const root = `${dir}/../..`;
7
- import config from '../config.js';
8
-
9
9
  const isProduction = process.env.NODE_ENV === 'production' || config.production;
10
10
 
11
11
  async function plugin(fastify) {
@@ -33,8 +33,7 @@ async function plugin(fastify) {
33
33
  // this is middleware for vite's dev servert
34
34
  fastify.addHook('onRequest', async (req, reply) => {
35
35
  const { user } = req.session?.passport || {};
36
- const { disableAuth } = req.funcs?.config || {};
37
- if (!user && !disableAuth) {
36
+ if (!user && config.pg && !config.auth?.disable) {
38
37
  return reply.redirect('/login');
39
38
  }
40
39
 
@@ -50,9 +49,14 @@ async function plugin(fastify) {
50
49
  // From Build
51
50
  fastify.get('*', async (req, reply) => {
52
51
  const { user } = req.session?.passport || {};
53
- const assetsDir = '/dist';
54
- if (!user) return reply.redirect('/login');
55
- const stream = fs.createReadStream(`${assetsDir}/index.html`);
52
+ const indexPath = path.join(root, 'dist', 'index.html');
53
+ // if (!user && config.pg && !config.auth?.disable) {
54
+ // return reply.redirect('/login');
55
+ // }
56
+ if (!fs.existsSync(indexPath)) {
57
+ return reply.status(404).send('index.html not found');
58
+ }
59
+ const stream = fs.createReadStream(indexPath);
56
60
  return reply.type('text/html').send(stream);
57
61
  });
58
62
 
@@ -0,0 +1,60 @@
1
+ import { config, pgClients, dataDelete } from '@opengis/fastify-table/utils.js';
2
+
3
+ import builderCache from '../../contentType/utils/builderCache.js';
4
+
5
+ export default async function deleteContent(req, reply) {
6
+ const {
7
+ pg = pgClients.client,
8
+ params = {},
9
+ user = {},
10
+ headers = {},
11
+ } = req;
12
+
13
+ const { type, id } = params;
14
+
15
+ if (!type) {
16
+ return reply.status(400).send('not enough params: type');
17
+ }
18
+
19
+ if (!id) {
20
+ return reply.status(400).send('not enough params: id');
21
+ }
22
+
23
+ if (builderCache[type]?.table && builderCache[type]?.provider === 'pg' && config.pg) {
24
+ const result = await dataDelete({
25
+ pg,
26
+ id,
27
+ table: 'site.' + builderCache[type]?.table,
28
+ referer: headers?.referer,
29
+ uid: user?.uid || 0,
30
+ });
31
+
32
+ const pk = pg.pk?.['site.' + builderCache[type]?.table];
33
+ return reply.status(200).send({ id: result?.[pk], ...result || {} });
34
+ }
35
+
36
+ const arr = config.pg ? await pg.query(`select array_agg(relname)::text[] from pg_class a
37
+ left join pg_namespace b on a.relnamespace=b.oid
38
+ where a.relam=2 and b.nspname='site'`).then(el => el.rows?.[0]?.array_agg || []) : [];
39
+
40
+ if (!arr.length) {
41
+ return reply.status(400).send('empty schema: site');
42
+ }
43
+
44
+ const table = arr.find(el => el === params.type);
45
+
46
+ if (!table) {
47
+ return reply.status(400).send('invalid params: type');
48
+ }
49
+
50
+ const result = await dataDelete({
51
+ pg,
52
+ id,
53
+ table: 'site.' + table,
54
+ referer: headers?.referer,
55
+ uid: user?.uid || 0,
56
+ });
57
+
58
+ const pk = pg.pk?.['site.' + table];
59
+ return reply.status(200).send({ id: result?.[pk], ...result || {} });
60
+ }
@@ -1,47 +1,47 @@
1
- import path from 'node:path';
2
- import { existsSync } from 'node:fs';
3
- import { rm } from 'node:fs/promises';
4
-
5
- import { config, dataDelete, getFolder, pgClients } from "@opengis/fastify-table/utils.js";
6
-
7
- const rootDir = getFolder(config, 'local');
8
-
9
- export default async function deleteMedia({
10
- pg = pgClients.client, params = {}, user = {}, method = 'DELETE',
11
- }, reply) {
12
- if (!config.debug && method !== 'DELETE') {
13
- return reply.status(403).send('access restricted');
14
- }
15
-
16
- if (!params?.id) {
17
- return reply.status(400).send('not enough params: id');
18
- }
19
-
20
- if (!pg.pk?.['site.media']) {
21
- return reply.status(404).send('table not found');
22
- }
23
-
24
- const { url: relpath, id } = await pg.query(
25
- 'select media_id as id, url from site.media where media_id = $1 and url is not null',
26
- [params.id],
27
- ).then(el => el.rows?.[0] || {});
28
-
29
- if (!id) {
30
- return reply.status(404).send('media not found: ' + params.id);
31
- }
32
-
33
- const res = await dataDelete({
34
- pg,
35
- id,
36
- table: 'site.media',
37
- uid: user?.uid || 0,
38
- });
39
-
40
- const filepath = path.join(rootDir, relpath);
41
-
42
- if (existsSync(filepath)) {
43
- await rm(filepath, { recursive: true });
44
- }
45
-
46
- return { id, ...res || {} };
1
+ import path from 'node:path';
2
+ import { existsSync } from 'node:fs';
3
+ import { rm } from 'node:fs/promises';
4
+
5
+ import { config, dataDelete, getFolder, pgClients } from "@opengis/fastify-table/utils.js";
6
+
7
+ const rootDir = getFolder(config, 'local');
8
+
9
+ export default async function deleteMedia({
10
+ pg = pgClients.client, params = {}, user = {}, method = 'DELETE',
11
+ }, reply) {
12
+ if (!config.debug && method !== 'DELETE') {
13
+ return reply.status(403).send('access restricted');
14
+ }
15
+
16
+ if (!params?.id) {
17
+ return reply.status(400).send('not enough params: id');
18
+ }
19
+
20
+ if (!pg.pk?.['site.media']) {
21
+ return reply.status(404).send('table not found');
22
+ }
23
+
24
+ const { url: relpath, id } = await pg.query(
25
+ 'select media_id as id, url from site.media where media_id = $1 and url is not null',
26
+ [params.id],
27
+ ).then(el => el.rows?.[0] || {});
28
+
29
+ if (!id) {
30
+ return reply.status(404).send('media not found: ' + params.id);
31
+ }
32
+
33
+ const res = await dataDelete({
34
+ pg,
35
+ id,
36
+ table: 'site.media',
37
+ uid: user?.uid || 0,
38
+ });
39
+
40
+ const filepath = path.join(rootDir, relpath);
41
+
42
+ if (existsSync(filepath)) {
43
+ await rm(filepath, { recursive: true });
44
+ }
45
+
46
+ return { id, ...res || {} };
47
47
  }
@@ -1,48 +1,48 @@
1
- import path from 'node:path';
2
- import { existsSync } from 'node:fs';
3
- import { readFile } from 'node:fs/promises';
4
-
5
- import { config, getFolder, pgClients } from "@opengis/fastify-table/utils.js";
6
-
7
- const rootDir = getFolder(config, 'local');
8
-
9
- export default async function downloadMedia({
10
- pg = pgClients.client, params = {}, query = {},
11
- }, reply) {
12
- if (!params?.id) {
13
- return reply.status(400).send('not enough params: id');
14
- }
15
-
16
- if (!pg.pk?.['site.media']) {
17
- return reply.status(404).send('table not found');
18
- }
19
-
20
- const { filename, mime, id, url: relpath } = await pg.query(
21
- 'select media_id as id, filename, mime, url from site.media where media_id = $1 and url is not null',
22
- [params.id],
23
- ).then(el => el.rows?.[0] || {});
24
-
25
- if (!id) {
26
- return reply.status(404).send('media not found: ' + params.id);
27
- }
28
-
29
- const filepath = path.join(rootDir, relpath);
30
-
31
- if (!existsSync(filepath)) {
32
- return reply.status(404).send('file not found');
33
- }
34
-
35
- const buffer = await readFile(filepath, { buffer: true });
36
-
37
- // skip xml load for preview
38
- if (query.preview && path.extname(filename) !== '.xml') {
39
- return reply.headers({ 'Content-Type': mime }).send(buffer);
40
- }
41
-
42
- return reply
43
- .headers({
44
- 'Content-Type': mime,
45
- 'Content-Disposition': `attachment; filename=${filename || path.basename(filepath)}`,
46
- })
47
- .send(buffer);
48
- }
1
+ import path from 'node:path';
2
+ import { existsSync } from 'node:fs';
3
+ import { readFile } from 'node:fs/promises';
4
+
5
+ import { config, getFolder, pgClients } from "@opengis/fastify-table/utils.js";
6
+
7
+ const rootDir = getFolder(config, 'local');
8
+
9
+ export default async function downloadMedia({
10
+ pg = pgClients.client, params = {}, query = {},
11
+ }, reply) {
12
+ if (!params?.id) {
13
+ return reply.status(400).send('not enough params: id');
14
+ }
15
+
16
+ if (!pg.pk?.['site.media']) {
17
+ return reply.status(404).send('table not found');
18
+ }
19
+
20
+ const { filename, mime, id, url: relpath } = await pg.query(
21
+ 'select media_id as id, filename, mime, url from site.media where media_id = $1 and url is not null',
22
+ [params.id],
23
+ ).then(el => el.rows?.[0] || {});
24
+
25
+ if (!id) {
26
+ return reply.status(404).send('media not found: ' + params.id);
27
+ }
28
+
29
+ const filepath = path.join(rootDir, relpath);
30
+
31
+ if (!existsSync(filepath)) {
32
+ return reply.status(404).send('file not found');
33
+ }
34
+
35
+ const buffer = await readFile(filepath, { buffer: true });
36
+
37
+ // skip xml load for preview
38
+ if (query.preview && path.extname(filename) !== '.xml') {
39
+ return reply.headers({ 'Content-Type': mime }).send(buffer);
40
+ }
41
+
42
+ return reply
43
+ .headers({
44
+ 'Content-Type': mime,
45
+ 'Content-Disposition': `attachment; filename=${filename || path.basename(filepath)}`,
46
+ })
47
+ .send(buffer);
48
+ }
@@ -0,0 +1,96 @@
1
+ import { config, pgClients, getData, getMeta } from '@opengis/fastify-table/utils.js';
2
+
3
+ import builderCache from '../../contentType/utils/builderCache.js';
4
+
5
+ const maxLimit = 100;
6
+
7
+ const matches = {
8
+ 16: 'yes_no', // boolean
9
+ 701: 'number', // double precision
10
+ 1082: 'date', // date
11
+ 1184: 'date', // timestamp w/ time zone
12
+ 1114: 'date', // timestamp w/o time zone
13
+ 1700: 'number', // numeric
14
+ };
15
+
16
+ export default async function getContent(req, reply) {
17
+ const { pg = pgClients.client, params = {}, query = {}, user = {} } = req;
18
+ const { type, id } = params;
19
+ const { filter, state, limit = 16, page, search, order, sql } = query;
20
+
21
+ if (!type) {
22
+ return reply.status(400).send('not enough params: type');
23
+ }
24
+
25
+ if (type === 'single' && id) {
26
+ const cache = builderCache(id) || {};
27
+ const row = await pg.query('select json_object_agg(key, value) from site.single_type_values where type_name=$1', [id])
28
+ .then(el => el.rows?.[0]?.json_object_agg);
29
+ if (row) Object.assign(row, { id });
30
+ return {
31
+ pk: 'id',
32
+ title: cache?.title || id,
33
+ id,
34
+ columns: Object.entries(cache?.columns || {}).map(el => ({ name: el[0], ...el[1] })) || [],
35
+ rows: [row].filter(Boolean),
36
+ };
37
+ }
38
+
39
+ const builderData = builderCache(type);
40
+
41
+ if (builderData?.table && builderData?.provider === 'pg' && config.pg) {
42
+ const { columns = [] } = await getMeta({ pg, table: 'site.' + builderData.table });
43
+ const res = await getData({
44
+ pg,
45
+ id,
46
+ table: 'site.' + builderData.table,
47
+ filter,
48
+ state,
49
+ limit: Math.min(limit, maxLimit),
50
+ page,
51
+ search,
52
+ order,
53
+ sql,
54
+ user,
55
+ }, reply, 1);
56
+
57
+ if (columns?.length) {
58
+ columns.forEach(el => {
59
+ el.type = matches[el.dataTypeID] || 'text';
60
+ el.hidden = !Object.keys((builderCache(type))?.columns || {}).includes(el.name);
61
+ });
62
+ }
63
+
64
+ return { ...res || {}, columns: columns.filter(el => !el.hidden).map(({ name, title, type }) => ({ name, title, type })) };
65
+ }
66
+
67
+ const arr = config.pg ? await pg.query(`select array_agg(relname)::text[] from pg_class a
68
+ left join pg_namespace b on a.relnamespace=b.oid
69
+ where a.relam=2 and b.nspname='site'`).then(el => el.rows?.[0]?.array_agg || []) : [];
70
+
71
+ if (!arr.length) {
72
+ return reply.status(400).send('empty schema: site');
73
+ }
74
+
75
+ const table = arr.find(el => el === params.type);
76
+
77
+ if (!table) {
78
+ return reply.status(400).send('invalid params: type');
79
+ }
80
+
81
+ const res = await getData({
82
+ pg,
83
+ id,
84
+ table: 'site.' + table,
85
+ filter,
86
+ state,
87
+ limit: Math.min(limit, maxLimit),
88
+ page,
89
+ search,
90
+ order,
91
+ sql,
92
+ user,
93
+ }, reply, 1);
94
+
95
+ return res;
96
+ }
@@ -1,16 +1,16 @@
1
- import { pgClients } from '@opengis/fastify-table/utils.js';
2
-
3
- export default async function getPermissions(req, reply) {
4
- const { pg = pgClients.client, params = {}, user = {} } = req;
5
-
6
- if (!user?.uid) {
7
- return reply.status(401).send('unauthorized');
8
- }
9
-
10
- const { rows = [] } = await pg.query(
11
- `select * from site.permissions where ${params.id ? 'user_id=$1' : 'true'}`,
12
- [params.id].filter(Boolean),
13
- );
14
-
15
- return { permissions: rows };
1
+ import { pgClients } from '@opengis/fastify-table/utils.js';
2
+
3
+ export default async function getPermissions(req, reply) {
4
+ const { pg = pgClients.client, params = {}, user = {} } = req;
5
+
6
+ if (!user?.uid) {
7
+ return reply.status(401).send('unauthorized');
8
+ }
9
+
10
+ const { rows = [] } = await pg.query(
11
+ `select * from site.permissions where ${params.id ? 'user_id=$1' : 'true'}`,
12
+ [params.id].filter(Boolean),
13
+ );
14
+
15
+ return { permissions: rows };
16
16
  }
@@ -0,0 +1,69 @@
1
+ import { config, pgClients, dataInsert } from '@opengis/fastify-table/utils.js';
2
+
3
+ import builderCache from '../../contentType/utils/builderCache.js';
4
+
5
+ export default async function insertContent(req, reply) {
6
+ const {
7
+ pg = pgClients.client,
8
+ params = {},
9
+ user = {},
10
+ body = {},
11
+ headers = {},
12
+ } = req;
13
+
14
+ const { type, id = body?.id } = params;
15
+
16
+ if (!type) {
17
+ return reply.status(400).send('not enough params: type');
18
+ }
19
+
20
+ if (builderCache[type]?.table && builderCache[type]?.provider === 'pg' && config.pg) {
21
+ const { rows = [] } = await dataInsert({
22
+ pg,
23
+ id,
24
+ table: 'site.' + builderCache[type]?.table,
25
+ data: body,
26
+ referer: headers?.referer,
27
+ uid: user?.uid || 0,
28
+ }).catch(err => {
29
+ if (err.message?.includes?.('unique constraint')) {
30
+ return reply.status(400).send('Порушенні унікальності: ' + err.message?.match?.(/([^"]+)/g)?.[1]);
31
+ }
32
+ return reply.status(500).send(err.toString());
33
+ });
34
+
35
+ const pk = pg.pk?.['site.' + builderCache[type]?.table];
36
+ return reply.status(200).send({ id: rows[0]?.[pk], rows });
37
+ }
38
+
39
+ const arr = config.pg ? await pg.query(`select array_agg(relname)::text[] from pg_class a
40
+ left join pg_namespace b on a.relnamespace=b.oid
41
+ where a.relam=2 and b.nspname='site'`).then(el => el.rows?.[0]?.array_agg || []) : [];
42
+
43
+ if (!arr.length) {
44
+ return reply.status(400).send('empty schema: site');
45
+ }
46
+
47
+ const table = arr.find(el => el === params.type);
48
+
49
+ if (!table) {
50
+ return reply.status(400).send('invalid params: type');
51
+ }
52
+
53
+ const { rows = [] } = await dataInsert({
54
+ pg,
55
+ id,
56
+ table: 'site.' + table,
57
+ data: body,
58
+ referer: headers?.referer,
59
+ uid: user?.uid || 0,
60
+ }).catch(err => {
61
+ if (err.message?.includes?.('unique constraint')) {
62
+ return reply.status(400).send('Порушенні унікальності: ' + err.message?.match?.(/([^"]+)/g)?.[1]);
63
+ }
64
+ return reply.status(500).send(err.toString());
65
+ });
66
+
67
+ const pk = pg.pk?.['site.' + table];
68
+ return reply.status(200).send({ id: rows[0]?.[pk], rows });
69
+ }