@opengis/cms 0.0.26 → 0.0.28

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 (90) hide show
  1. package/README.md +98 -98
  2. package/dist/index-W-qQIppj-DunG40EG.js +2452 -0
  3. package/dist/index.html +28 -28
  4. package/dist/index.js +12683 -6702
  5. package/dist/index.umd.cjs +87 -41
  6. package/dist/style.css +1 -0
  7. package/package.json +68 -68
  8. package/plugin.js +76 -76
  9. package/server/app.js +35 -35
  10. package/server/config.js +4 -4
  11. package/server/functions/getDraftKey.js +22 -22
  12. package/server/index.js +22 -22
  13. package/server/migrations/fixes.sql +123 -123
  14. package/server/migrations/site.sql +545 -545
  15. package/server/plugins/adminHook.js +78 -78
  16. package/server/plugins/hook.js +59 -59
  17. package/server/plugins/vite.js +84 -84
  18. package/server/routes/category/controllers/cms.category.delete.js +21 -21
  19. package/server/routes/category/controllers/cms.category.get.js +17 -17
  20. package/server/routes/category/controllers/cms.category.list.js +16 -16
  21. package/server/routes/category/controllers/cms.category.post.js +21 -21
  22. package/server/routes/category/controllers/cms.category.put.js +23 -23
  23. package/server/routes/category/index.mjs +22 -22
  24. package/server/routes/cms/controllers/cmsStat.js +55 -55
  25. package/server/routes/cms/controllers/cmsSuggest.js +57 -57
  26. package/server/routes/cms/controllers/deleteContent.js +114 -114
  27. package/server/routes/cms/controllers/deleteMedia.js +75 -75
  28. package/server/routes/cms/controllers/downloadMedia.js +48 -48
  29. package/server/routes/cms/controllers/getContent.js +110 -110
  30. package/server/routes/cms/controllers/getContentBySlug.js +95 -95
  31. package/server/routes/cms/controllers/getPermissions.js +15 -15
  32. package/server/routes/cms/controllers/insertContent.js +218 -218
  33. package/server/routes/cms/controllers/listMedia.js +93 -93
  34. package/server/routes/cms/controllers/metadataMedia.js +38 -38
  35. package/server/routes/cms/controllers/properties.get.js +53 -53
  36. package/server/routes/cms/controllers/properties.post.js +99 -99
  37. package/server/routes/cms/controllers/searchContent.js +205 -205
  38. package/server/routes/cms/controllers/setPermissions.js +49 -49
  39. package/server/routes/cms/controllers/translate.js +89 -89
  40. package/server/routes/cms/controllers/updateContent.js +238 -238
  41. package/server/routes/cms/controllers/uploadMedia.js +78 -78
  42. package/server/routes/cms/index.mjs +114 -114
  43. package/server/routes/cms/utils/additionalData.js +35 -35
  44. package/server/routes/cms/utils/getCollection.js +81 -81
  45. package/server/routes/cms/utils/getSingle.js +187 -187
  46. package/server/routes/cms/utils/insertContentLocalization.js +86 -86
  47. package/server/routes/cms/utils/requestTranslation.js +85 -85
  48. package/server/routes/cms/utils/updateLocalization.js +47 -47
  49. package/server/routes/cmsSpace/controllers/deleteSpace.js +25 -25
  50. package/server/routes/cmsSpace/controllers/getSpaces.js +27 -27
  51. package/server/routes/cmsSpace/controllers/insertSpace.js +21 -21
  52. package/server/routes/cmsSpace/controllers/updateSpace.js +23 -23
  53. package/server/routes/cmsSpace/index.mjs +20 -20
  54. package/server/routes/contentType/controllers/addContentType.js +162 -162
  55. package/server/routes/contentType/controllers/contentTypeList.js +54 -54
  56. package/server/routes/contentType/controllers/delContentType.js +75 -75
  57. package/server/routes/contentType/controllers/editContentType.js +61 -61
  58. package/server/routes/contentType/controllers/getContentType.js +37 -37
  59. package/server/routes/contentType/index.mjs +35 -35
  60. package/server/routes/contentType/utils/updateContents.js +28 -28
  61. package/server/routes/contentType/utils/updateCustomContentTable.js +55 -55
  62. package/server/routes/feedback/controllers/email.list.js +24 -24
  63. package/server/routes/feedback/controllers/feedback.js +48 -48
  64. package/server/routes/feedback/controllers/feedback.list.js +37 -37
  65. package/server/routes/feedback/controllers/news.subscriptions.js +44 -44
  66. package/server/routes/feedback/index.mjs +71 -71
  67. package/server/routes/logs/controllers/export.user.logs.js +77 -77
  68. package/server/routes/logs/controllers/user.logs.js +44 -44
  69. package/server/routes/logs/index.mjs +9 -9
  70. package/server/routes/menu/controllers/addMenu.js +37 -37
  71. package/server/routes/menu/controllers/delMenu.js +31 -31
  72. package/server/routes/menu/controllers/editMenu.js +41 -41
  73. package/server/routes/menu/controllers/getMenu.js +42 -42
  74. package/server/routes/menu/index.mjs +13 -13
  75. package/server/routes/migration/controllers/collectionToCustom.js +137 -137
  76. package/server/routes/migration/index.mjs +8 -8
  77. package/server/routes/root.mjs +8 -8
  78. package/server/routes/tags/controllers/add.tags.js +24 -24
  79. package/server/routes/tags/controllers/del.tags.js +19 -19
  80. package/server/routes/tags/controllers/edit.tags.js +25 -25
  81. package/server/routes/tags/controllers/get.tags.js +15 -15
  82. package/server/routes/tags/index.mjs +14 -14
  83. package/server/templates/cls/cms.category_type.json +9 -9
  84. package/server/templates/cls/cms.content_review_status.json +9 -9
  85. package/server/templates/cls/cms.content_status.json +9 -9
  86. package/server/templates/cls/cms.content_type.json +9 -9
  87. package/server/templates/cls/cms.lang.json +9 -9
  88. package/server/templates/page/login.html +126 -126
  89. package/server/templates/select/core.user_mentioned.sql +1 -1
  90. package/dist/index-W-qQIppj-DRzFSjU1.js +0 -2452
@@ -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 = {},
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 (params.type === '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 = {},
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 (params.type === '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,111 +1,111 @@
1
- import { config, pgClients, addHook, getTemplate } from '@opengis/fastify-table/utils.js';
2
-
3
- import getCollection from '../utils/getCollection.js';
4
- import getSingle from '../utils/getSingle.js';
5
- import getDraftKey from '../../../functions/getDraftKey.js';
6
-
7
- const maxLimit = 100;
8
-
9
- addHook('preFilter', async ({ pg = pgClients.client, table }) => {
10
- if (config.trace) console.log('preFilter', table);
11
- if (!pg || !table) return null;
12
-
13
- if (!table.startsWith('data.') && ['site.contents', 'single.default.table'].includes(table)) {
14
- const { filters = [] } = await getTemplate('table', 'single.default.table') || {};
15
- return { table: 'site.contents', filters };
16
- }
17
-
18
- // default filters, same as pages collection
19
- const { filters = [] } = await getTemplate('table', 'collection.default.table') || {};
20
-
21
- if (['site.contents', 'collection.default.table'].includes(table)) {
22
- return { table: 'site.contents', filters };
23
- }
24
-
25
- if (table.startsWith('data.') && pg?.pk?.[table.replace(/"/g, '')]) {
26
- const { ctid, columns } = await pg.query(
27
- `select content_type_id as ctid, columns from site.content_types where 'data.' || table_name = $1`,
28
- [table.replace(/"/g, '')]
29
- ).then(el => el.rows?.[0] || {});
30
- if (!ctid) return null;
31
-
32
- return { table, filters: filters.concat((columns || []).filter(el => !el.hidden && el.filter && el.name && filters.map(item => item.name).includes(el.name))) };
33
- }
34
- });
35
-
36
- const defaultFields = ['title', 'slug', 'status', 'created_at', 'updated_at', 'main_image', 'published_at'];
37
-
38
- export default async function getContent(req, reply) {
39
- const { pg = pgClients.client, params = {}, query = {}, headers = {} } = req;
40
- const user = req.user || {};
41
- const { type, id } = params;
42
- const { filter, state, limit = 16, page, sql, contextQuery, locale, tags, fields } = query;
43
- const search = filter ? filter?.split?.('search=')?.[1]?.split?.('|')?.[0] : undefined;
44
- const [order, ord] = query.order?.split?.('-') || [];
45
- const desc = query.desc || ord === 'desc';
46
-
47
- const { draftKey } = await getDraftKey();
48
- const showDrafts = query.draftKey && query.draftKey === draftKey;
49
- const statusQuery = !!req.user?.uid || showDrafts ? '1=1' : `status='published'`;
50
-
51
- // headers.authorization = 'Bearer tokenExample'
52
- const isValidToken = await pg.query(
53
- `select count(*) = 1 as isvalid from site.tokens where token_value=$1 and token_status = 'Active'`,
54
- [headers.authorization?.split(' ')?.pop?.() || '']
55
- ).then(el => el.rows?.[0]?.isvalid);
56
-
57
- if (!config.local && !isValidToken && config.mode !== 'cms') {
58
- return reply.status(403).send('access restricted: token');
59
- }
60
-
61
- if (!type) {
62
- return reply.status(400).send('not enough params: type');
63
- }
64
-
65
- const { contentId, contentTypeId, meta } = params.type === 'pages'
66
- ? await pg.query(`select content_id as "contentId", content_type_id as "contentTypeId", meta from site.contents where content_id=$1`, [params.type]).then(el => el.rows?.[0] || {})
67
- : await pg.query(`select content_id as "contentId", content_type_id as "contentTypeId", meta from site.contents where $1 in (slug, content_id, content_type_id)`, [params.type]).then(el => el.rows?.[0] || {});
68
-
69
- if (!contentId) {
70
- return reply.status(404).send('content not found');
71
- }
72
-
73
- const { table, contentType, preview, columns: columns1 } = await pg.query(
74
- 'select table_name as table, type as "contentType", preview_path as preview, columns from site.content_types where content_type_id=$1',
75
- [contentTypeId],
76
- ).then(el => el.rows?.[0] || {});
77
-
78
- if (!contentType) {
79
- return reply.status(404).send('content type not found');
80
- }
81
-
82
- const loadTable = contentType === 'collection' && table
83
- ? await getTemplate('table', 'collection.default.table')
84
- : await getTemplate('table', 'single.default.table');
85
- const { columns: defaultColumns = [], filters: defaultFilters = [] } = loadTable || {};
86
-
87
- defaultColumns.forEach(col => Object.assign(col, { default: true }));
88
-
89
- const columns = columns1.filter(col => !defaultColumns.map(el => el.name).includes(col.name));
90
-
91
- const result = contentType === 'collection' && table
92
- ? await getCollection({
93
- table, id, limit, maxLimit, tags, order, search, filter, state, page, desc,
94
- sql, locale, contextQuery, statusQuery, columns, preview, user, defaultColumns, fields, defaultFields, defaultFilters,
95
- }, reply, pg)
96
- : await getSingle({
97
- contentId, id, limit, maxLimit, tags, search, filter, locale, statusQuery, user, sql, page, defaultColumns, fields, defaultFields, defaultFilters,
98
- }, pg);
99
-
100
- if (!result) {
101
- return reply.status(404).send('empty content data');
102
- }
103
-
104
- if (result?.message) {
105
- return reply.status(result.status || 500).send(result.message);
106
- }
107
-
108
- Object.assign(result, { meta });
109
-
110
- return reply.status(200).send(result);
1
+ import { config, pgClients, addHook, getTemplate } from '@opengis/fastify-table/utils.js';
2
+
3
+ import getCollection from '../utils/getCollection.js';
4
+ import getSingle from '../utils/getSingle.js';
5
+ import getDraftKey from '../../../functions/getDraftKey.js';
6
+
7
+ const maxLimit = 100;
8
+
9
+ addHook('preFilter', async ({ pg = pgClients.client, table }) => {
10
+ if (config.trace) console.log('preFilter', table);
11
+ if (!pg || !table) return null;
12
+
13
+ if (!table.startsWith('data.') && ['site.contents', 'single.default.table'].includes(table)) {
14
+ const { filters = [] } = await getTemplate('table', 'single.default.table') || {};
15
+ return { table: 'site.contents', filters };
16
+ }
17
+
18
+ // default filters, same as pages collection
19
+ const { filters = [] } = await getTemplate('table', 'collection.default.table') || {};
20
+
21
+ if (['site.contents', 'collection.default.table'].includes(table)) {
22
+ return { table: 'site.contents', filters };
23
+ }
24
+
25
+ if (table.startsWith('data.') && pg?.pk?.[table.replace(/"/g, '')]) {
26
+ const { ctid, columns } = await pg.query(
27
+ `select content_type_id as ctid, columns from site.content_types where 'data.' || table_name = $1`,
28
+ [table.replace(/"/g, '')]
29
+ ).then(el => el.rows?.[0] || {});
30
+ if (!ctid) return null;
31
+
32
+ return { table, filters: filters.concat((columns || []).filter(el => !el.hidden && el.filter && el.name && filters.map(item => item.name).includes(el.name))) };
33
+ }
34
+ });
35
+
36
+ const defaultFields = ['title', 'slug', 'status', 'created_at', 'updated_at', 'main_image', 'published_at'];
37
+
38
+ export default async function getContent(req, reply) {
39
+ const { pg = pgClients.client, params = {}, query = {}, headers = {} } = req;
40
+ const user = req.user || {};
41
+ const { type, id } = params;
42
+ const { filter, state, limit = 16, page, sql, contextQuery, locale, tags, fields } = query;
43
+ const search = filter ? filter?.split?.('search=')?.[1]?.split?.('|')?.[0] : undefined;
44
+ const [order, ord] = query.order?.split?.('-') || [];
45
+ const desc = query.desc || ord === 'desc';
46
+
47
+ const { draftKey } = await getDraftKey();
48
+ const showDrafts = query.draftKey && query.draftKey === draftKey;
49
+ const statusQuery = !!req.user?.uid || showDrafts ? '1=1' : `status='published'`;
50
+
51
+ // headers.authorization = 'Bearer tokenExample'
52
+ const isValidToken = await pg.query(
53
+ `select count(*) = 1 as isvalid from site.tokens where token_value=$1 and token_status = 'Active'`,
54
+ [headers.authorization?.split(' ')?.pop?.() || '']
55
+ ).then(el => el.rows?.[0]?.isvalid);
56
+
57
+ if (!config.local && !isValidToken && config.mode !== 'cms') {
58
+ return reply.status(403).send('access restricted: token');
59
+ }
60
+
61
+ if (!type) {
62
+ return reply.status(400).send('not enough params: type');
63
+ }
64
+
65
+ const { contentId, contentTypeId, meta } = params.type === 'pages'
66
+ ? await pg.query(`select content_id as "contentId", content_type_id as "contentTypeId", meta from site.contents where content_id=$1`, [params.type]).then(el => el.rows?.[0] || {})
67
+ : await pg.query(`select content_id as "contentId", content_type_id as "contentTypeId", meta from site.contents where $1 in (slug, content_id, content_type_id)`, [params.type]).then(el => el.rows?.[0] || {});
68
+
69
+ if (!contentId) {
70
+ return reply.status(404).send('content not found');
71
+ }
72
+
73
+ const { table, contentType, preview, columns: columns1 } = await pg.query(
74
+ 'select table_name as table, type as "contentType", preview_path as preview, columns from site.content_types where content_type_id=$1',
75
+ [contentTypeId],
76
+ ).then(el => el.rows?.[0] || {});
77
+
78
+ if (!contentType) {
79
+ return reply.status(404).send('content type not found');
80
+ }
81
+
82
+ const loadTable = contentType === 'collection' && table
83
+ ? await getTemplate('table', 'collection.default.table')
84
+ : await getTemplate('table', 'single.default.table');
85
+ const { columns: defaultColumns = [], filters: defaultFilters = [] } = loadTable || {};
86
+
87
+ defaultColumns.forEach(col => Object.assign(col, { default: true }));
88
+
89
+ const columns = columns1.filter(col => !defaultColumns.map(el => el.name).includes(col.name));
90
+
91
+ const result = contentType === 'collection' && table
92
+ ? await getCollection({
93
+ table, id, limit, maxLimit, tags, order, search, filter, state, page, desc,
94
+ sql, locale, contextQuery, statusQuery, columns, preview, user, defaultColumns, fields, defaultFields, defaultFilters,
95
+ }, reply, pg)
96
+ : await getSingle({
97
+ contentId, id, limit, maxLimit, tags, search, filter, locale, statusQuery, user, sql, page, defaultColumns, fields, defaultFields, defaultFilters,
98
+ }, pg);
99
+
100
+ if (!result) {
101
+ return reply.status(404).send('empty content data');
102
+ }
103
+
104
+ if (result?.message) {
105
+ return reply.status(result.status || 500).send(result.message);
106
+ }
107
+
108
+ Object.assign(result, { meta });
109
+
110
+ return reply.status(200).send(result);
111
111
  }
@@ -1,95 +1,95 @@
1
- import { existsSync, readFileSync } from 'node:fs';
2
-
3
- import { config, pgClients } from '@opengis/fastify-table/utils.js';
4
-
5
- const inputTypes = existsSync('input-types.json') ? JSON.parse(readFileSync('input-types.json') || '{}') : {};
6
-
7
- export default async function getContentBySlug({ pg = pgClients.client, params = {}, headers = {} }, reply) {
8
- if (!params.slug) {
9
- return reply.status(400).send('not enough params: slug');
10
- }
11
-
12
- if (!pg?.pk?.['site.content_types']) {
13
- return reply.status(404).send('table not found');
14
- }
15
-
16
- // headers.authorization = 'Bearer tokenExample'
17
- const isValidToken = await pg.query(
18
- `select count(*) = 1 as isvalid from site.tokens where token_value=$1 and token_status = 'Active'`,
19
- [headers.authorization?.split(' ')?.pop?.() || '']
20
- ).then(el => el.rows?.[0]?.isvalid);
21
-
22
- if (!config.local && !isValidToken && config.mode !== 'cms') {
23
- return reply.status(403).send('access restricted: token');
24
- }
25
-
26
- const { cid } = await pg.query(
27
- `select content_id as cid from site.contents where $1 in (content_id,slug) limit 1`,
28
- [params.slug],
29
- ).then(el => el.rows?.[0] || {});
30
-
31
- if (cid) {
32
- const { rows: data = [] } = await pg.query(
33
- `select field_key, field_type, field_value, field_value_object, content_id from site.content_data where content_id=$1`, [cid]
34
- );
35
-
36
- const meta = await pg.query(
37
- 'select title, status, revision, locale, slug, content_type_id, (select columns from site.content_types where content_type_id=a.content_type_id limit 1) as columns from site.contents a where content_id=$1 limit 1',
38
- [cid],
39
- ).then(el => el.rows?.[0] || {});
40
-
41
- const rows = meta.content_type_id ? [{
42
- ...meta,
43
- columns: undefined,
44
- ...Object.fromEntries(
45
- data.map(k =>
46
- [k.field_key, inputTypes[k.field_type] === 'json' || k.field_key === 'meta'
47
- ? k.field_value_object
48
- : k.field_value]
49
- ) || []
50
- )
51
- }] : [];
52
-
53
- const meta1 = meta.content_type_id ? await pg.query(
54
- 'select type from site.content_types where content_type_id=$1',
55
- [meta.content_type_id],
56
- ).then(el => el.rows?.[0] || {}) : {};
57
-
58
- return reply.status(200).send({
59
- ...meta,
60
- ...meta1,
61
- rows,
62
- });
63
- }
64
-
65
- const { rows: contentTypes = [] } = await pg.query(`select content_type_id as ctid, table_name as table, type from site.content_types where table_name is not null and type='collection' `);
66
-
67
- if (!contentTypes.length || contentTypes.find(row => row.table && pg.pk[row.table])) {
68
- return reply.status(404).send('content not found');
69
- }
70
-
71
- const tlist = await pg.query(`select array_agg((select nspname from pg_namespace where oid=relnamespace)||'.'||relname) tlist
72
- from pg_class where relkind in ('r','v')`).then((d) => d.rows[0].tlist);
73
-
74
- const q = contentTypes.filter(row => row.table && tlist.includes(`data.${row.table}`)).map(row => `select id as dataid, '${row.ctid}' as ctid from data."${row.table}" where slug='${params.slug.replace(/'/g, "''")}'`).join(' union all ');
75
-
76
- const { dataid, ctid } = await pg.query(q).then(el => el.rows?.[0] || {});
77
-
78
- if (!dataid) {
79
- return reply.status(404).send('content not found: 2');
80
- }
81
-
82
- if (!ctid) {
83
- return reply.status(404).send('content not found: 3');
84
- }
85
-
86
- const meta = await pg.query('select content_type_id, type, table_name as table, title, status, name as slug, columns from site.content_types where content_type_id=$1', [ctid]).then(el => el.rows?.[0] || {});
87
-
88
- if (!meta?.table) {
89
- return reply.status(404).send('content not found: 4');
90
- }
91
-
92
- const { rows = [] } = await pg.query(`select * from data.${meta.table} where id=$1`, [dataid]);
93
-
94
- return reply.status(200).send({ ...meta, custom: true, rows });
95
- }
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+
3
+ import { config, pgClients } from '@opengis/fastify-table/utils.js';
4
+
5
+ const inputTypes = existsSync('input-types.json') ? JSON.parse(readFileSync('input-types.json') || '{}') : {};
6
+
7
+ export default async function getContentBySlug({ pg = pgClients.client, params = {}, headers = {} }, reply) {
8
+ if (!params.slug) {
9
+ return reply.status(400).send('not enough params: slug');
10
+ }
11
+
12
+ if (!pg?.pk?.['site.content_types']) {
13
+ return reply.status(404).send('table not found');
14
+ }
15
+
16
+ // headers.authorization = 'Bearer tokenExample'
17
+ const isValidToken = await pg.query(
18
+ `select count(*) = 1 as isvalid from site.tokens where token_value=$1 and token_status = 'Active'`,
19
+ [headers.authorization?.split(' ')?.pop?.() || '']
20
+ ).then(el => el.rows?.[0]?.isvalid);
21
+
22
+ if (!config.local && !isValidToken && config.mode !== 'cms') {
23
+ return reply.status(403).send('access restricted: token');
24
+ }
25
+
26
+ const { cid } = await pg.query(
27
+ `select content_id as cid from site.contents where $1 in (content_id,slug) limit 1`,
28
+ [params.slug],
29
+ ).then(el => el.rows?.[0] || {});
30
+
31
+ if (cid) {
32
+ const { rows: data = [] } = await pg.query(
33
+ `select field_key, field_type, field_value, field_value_object, content_id from site.content_data where content_id=$1`, [cid]
34
+ );
35
+
36
+ const meta = await pg.query(
37
+ 'select title, status, revision, locale, slug, content_type_id, (select columns from site.content_types where content_type_id=a.content_type_id limit 1) as columns from site.contents a where content_id=$1 limit 1',
38
+ [cid],
39
+ ).then(el => el.rows?.[0] || {});
40
+
41
+ const rows = meta.content_type_id ? [{
42
+ ...meta,
43
+ columns: undefined,
44
+ ...Object.fromEntries(
45
+ data.map(k =>
46
+ [k.field_key, inputTypes[k.field_type] === 'json' || k.field_key === 'meta'
47
+ ? k.field_value_object
48
+ : k.field_value]
49
+ ) || []
50
+ )
51
+ }] : [];
52
+
53
+ const meta1 = meta.content_type_id ? await pg.query(
54
+ 'select type from site.content_types where content_type_id=$1',
55
+ [meta.content_type_id],
56
+ ).then(el => el.rows?.[0] || {}) : {};
57
+
58
+ return reply.status(200).send({
59
+ ...meta,
60
+ ...meta1,
61
+ rows,
62
+ });
63
+ }
64
+
65
+ const { rows: contentTypes = [] } = await pg.query(`select content_type_id as ctid, table_name as table, type from site.content_types where table_name is not null and type='collection' `);
66
+
67
+ if (!contentTypes.length || contentTypes.find(row => row.table && pg.pk[row.table])) {
68
+ return reply.status(404).send('content not found');
69
+ }
70
+
71
+ const tlist = await pg.query(`select array_agg((select nspname from pg_namespace where oid=relnamespace)||'.'||relname) tlist
72
+ from pg_class where relkind in ('r','v')`).then((d) => d.rows[0].tlist);
73
+
74
+ const q = contentTypes.filter(row => row.table && tlist.includes(`data.${row.table}`)).map(row => `select id as dataid, '${row.ctid}' as ctid from data."${row.table}" where slug='${params.slug.replace(/'/g, "''")}'`).join(' union all ');
75
+
76
+ const { dataid, ctid } = await pg.query(q).then(el => el.rows?.[0] || {});
77
+
78
+ if (!dataid) {
79
+ return reply.status(404).send('content not found: 2');
80
+ }
81
+
82
+ if (!ctid) {
83
+ return reply.status(404).send('content not found: 3');
84
+ }
85
+
86
+ const meta = await pg.query('select content_type_id, type, table_name as table, title, status, name as slug, columns from site.content_types where content_type_id=$1', [ctid]).then(el => el.rows?.[0] || {});
87
+
88
+ if (!meta?.table) {
89
+ return reply.status(404).send('content not found: 4');
90
+ }
91
+
92
+ const { rows = [] } = await pg.query(`select * from data.${meta.table} where id=$1`, [dataid]);
93
+
94
+ return reply.status(200).send({ ...meta, custom: true, rows });
95
+ }
@@ -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
  }