@opengis/cms 0.0.62 → 0.0.64

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 (124) hide show
  1. package/README.md +131 -131
  2. package/dist/{ArticlesPage-CFjE_cw_.js → ArticlesPage-BjYzvTWM.js} +3 -3
  3. package/dist/{CollectionsBreadcrumb-BCxeRikP.js → CollectionsBreadcrumb-HePNJb-d.js} +1 -1
  4. package/dist/CollectionsBreadcrumb.vue_vue_type_script_setup_true_lang-BJh-tjam.js +53 -0
  5. package/dist/{Dashboard-C1eGscNd.js → Dashboard-CXkg_pk8.js} +132 -132
  6. package/dist/{EditCollectionPage-C4uNmBJf.js → EditCollectionPage-CzFBw3wE.js} +3 -3
  7. package/dist/{MenuAddPage-D-p3gFgm.js → MenuAddPage-QTnwCoGh.js} +1 -1
  8. package/dist/{MenuBody-rN5j4YBu.js → MenuBody-Bi0ONVZf.js} +2 -2
  9. package/dist/{MenuItemPage-BoJw885D.js → MenuItemPage-B7Y9KFyb.js} +3 -3
  10. package/dist/{MenuList-DFEBS0NB.js → MenuList-BLIpeqSd.js} +53 -53
  11. package/dist/{MenuPage-BCZB_S8j.js → MenuPage-3W6jZ15H.js} +1 -1
  12. package/dist/{MenuWrapper-AZ_8s-zd.js → MenuWrapper-OrOv6sOb.js} +1 -1
  13. package/dist/{MonacoEditor-Db-3Jc3E.js → MonacoEditor-ByPT8pnv.js} +1 -1
  14. package/dist/MonacoEditor.vue_vue_type_script_setup_true_lang-C8cip9Ci.js +84 -0
  15. package/dist/{UniversalTable-CzqPG-tY.js → UniversalTable-GBd_pStq.js} +80 -80
  16. package/dist/{UniversalTablePagination-4gL47A7I.js → UniversalTablePagination-Dw2hc0nc.js} +46 -46
  17. package/dist/{contentForm-CcFbUeal.js → contentForm-CELj2rGf.js} +2 -2
  18. package/dist/index.js +5 -5
  19. package/dist/{vs-builder-monaco-B3Jj0V31.js → vs-builder-monaco-Cw-f19gc.js} +1 -1
  20. package/dist/{vs-builder-preview-DL3RYMp7.js → vs-builder-preview-BLfKnxhd.js} +1 -1
  21. package/dist/{vs-form-reference-list-Dtv8fJJU.js → vs-form-reference-list-DukrxeuH.js} +811 -364
  22. package/input-types.json +9 -9
  23. package/locales/en.json +823 -815
  24. package/locales/uk.json +821 -813
  25. package/module/cms/cls/content.status.json +17 -17
  26. package/module/cms/cls/user_type.json +9 -9
  27. package/module/cms/form/admin.users.form.json +77 -77
  28. package/module/cms/select/cms.page_type.sql +1 -1
  29. package/module/cms/select/news_tag_id.sql +11 -11
  30. package/module/cms/table/admin.users.table.json +53 -53
  31. package/module/cms/table/collection.default.table.json +96 -96
  32. package/module/cms/table/single.default.table.json +116 -116
  33. package/package.json +69 -69
  34. package/plugin.js +43 -43
  35. package/server/app.js +35 -35
  36. package/server/config.js +4 -4
  37. package/server/functions/getContent.js +45 -45
  38. package/server/functions/getDraftKey.js +22 -22
  39. package/server/functions/getSearchData.js +31 -31
  40. package/server/functions/getTags.js +30 -30
  41. package/server/functions/getUser.js +27 -27
  42. package/server/functions/utils/mock.reply.js +55 -55
  43. package/server/index.js +22 -22
  44. package/server/migrations/fixes.sql +132 -132
  45. package/server/migrations/site.sql +596 -596
  46. package/server/plugins/adminHook.js +78 -78
  47. package/server/plugins/hook.js +59 -59
  48. package/server/plugins/vite.js +75 -75
  49. package/server/routes/category/controllers/cms.category.delete.js +21 -21
  50. package/server/routes/category/controllers/cms.category.get.js +17 -17
  51. package/server/routes/category/controllers/cms.category.list.js +16 -16
  52. package/server/routes/category/controllers/cms.category.post.js +21 -21
  53. package/server/routes/category/controllers/cms.category.put.js +23 -23
  54. package/server/routes/category/index.mjs +22 -22
  55. package/server/routes/cms/controllers/cmsStat.js +55 -55
  56. package/server/routes/cms/controllers/cmsSuggest.js +57 -57
  57. package/server/routes/cms/controllers/deleteContent.js +113 -113
  58. package/server/routes/cms/controllers/downloadMedia.js +84 -84
  59. package/server/routes/cms/controllers/getContent.js +113 -113
  60. package/server/routes/cms/controllers/getContentBySlug.js +93 -93
  61. package/server/routes/cms/controllers/getPermissions.js +15 -15
  62. package/server/routes/cms/controllers/insertContent.js +226 -226
  63. package/server/routes/cms/controllers/listMedia.js +155 -155
  64. package/server/routes/cms/controllers/properties.get.js +18 -18
  65. package/server/routes/cms/controllers/properties.post.js +99 -99
  66. package/server/routes/cms/controllers/searchContent.js +214 -214
  67. package/server/routes/cms/controllers/setPermissions.js +49 -49
  68. package/server/routes/cms/controllers/translate.js +89 -89
  69. package/server/routes/cms/controllers/updateContent.js +231 -231
  70. package/server/routes/cms/functions/getSettings.js +48 -48
  71. package/server/routes/cms/index.mjs +112 -112
  72. package/server/routes/cms/utils/additionalData.js +35 -35
  73. package/server/routes/cms/utils/getCollection.js +89 -89
  74. package/server/routes/cms/utils/getSingle.js +188 -188
  75. package/server/routes/cms/utils/inputTypes.js +5 -5
  76. package/server/routes/cms/utils/insertContentLocalization.js +104 -104
  77. package/server/routes/cms/utils/requestTranslation.js +135 -135
  78. package/server/routes/cms/utils/updateLocalization.js +42 -42
  79. package/server/routes/cmsSpace/controllers/deleteSpace.js +26 -26
  80. package/server/routes/cmsSpace/controllers/getSpaces.js +28 -28
  81. package/server/routes/cmsSpace/controllers/insertSpace.js +22 -22
  82. package/server/routes/cmsSpace/controllers/updateSpace.js +24 -24
  83. package/server/routes/cmsSpace/index.mjs +20 -20
  84. package/server/routes/contentType/controllers/addContentType.js +160 -160
  85. package/server/routes/contentType/controllers/contentTypeList.js +47 -47
  86. package/server/routes/contentType/controllers/delContentType.js +75 -75
  87. package/server/routes/contentType/controllers/editContentType.js +70 -70
  88. package/server/routes/contentType/controllers/getContentType.js +57 -57
  89. package/server/routes/contentType/index.mjs +35 -35
  90. package/server/routes/contentType/utils/updateContents.js +44 -44
  91. package/server/routes/contentType/utils/updateCustomContentTable.js +53 -53
  92. package/server/routes/feedback/controllers/email.list.js +24 -24
  93. package/server/routes/feedback/controllers/feedback.js +48 -48
  94. package/server/routes/feedback/controllers/feedback.list.js +37 -37
  95. package/server/routes/feedback/controllers/news.subscriptions.js +44 -44
  96. package/server/routes/feedback/index.mjs +71 -71
  97. package/server/routes/logs/controllers/export.user.logs.js +77 -77
  98. package/server/routes/logs/controllers/user.logs.js +44 -44
  99. package/server/routes/logs/index.mjs +9 -9
  100. package/server/routes/menu/controllers/addMenu.js +37 -37
  101. package/server/routes/menu/controllers/delMenu.js +31 -31
  102. package/server/routes/menu/controllers/editMenu.js +41 -41
  103. package/server/routes/menu/controllers/getMenu.js +24 -24
  104. package/server/routes/menu/functions/getMenu.js +50 -50
  105. package/server/routes/menu/index.mjs +13 -13
  106. package/server/routes/migration/controllers/collectionToCustom.js +137 -137
  107. package/server/routes/migration/index.mjs +8 -8
  108. package/server/routes/root.mjs +8 -8
  109. package/server/routes/tags/controllers/add.tags.js +24 -24
  110. package/server/routes/tags/controllers/del.tags.js +19 -19
  111. package/server/routes/tags/controllers/edit.tags.js +25 -25
  112. package/server/routes/tags/controllers/get.tags.js +15 -15
  113. package/server/routes/tags/index.mjs +14 -14
  114. package/server/templates/cls/cms.category_type.json +9 -9
  115. package/server/templates/cls/cms.content_review_status.json +9 -9
  116. package/server/templates/cls/cms.content_status.json +9 -9
  117. package/server/templates/cls/cms.content_type.json +9 -9
  118. package/server/templates/cls/cms.lang.json +9 -9
  119. package/server/templates/page/login.html +126 -126
  120. package/server/templates/select/core.user_mentioned.sql +1 -1
  121. package/utils.d.ts +52 -52
  122. package/utils.js +8 -8
  123. package/dist/CollectionsBreadcrumb.vue_vue_type_script_setup_true_lang-umRzB5mY.js +0 -53
  124. package/dist/MonacoEditor.vue_vue_type_script_setup_true_lang-B1DrxmQX.js +0 -84
@@ -1,48 +1,48 @@
1
- import { config, pgClients, getRedis } from "@opengis/fastify-table/utils.js";
2
-
3
- const pg = pgClients.client;
4
- const rclient = getRedis();
5
-
6
- export default async function getSettings({ entity = 'app', keys = ['cms'], uid = 0, ttl = 3600 } = {}) {
7
- if (!pg) {
8
- return { error: "empty pg", code: 500 };
9
- }
10
-
11
- if (!pg.pk?.["admin.properties"]) {
12
- return { error: "properties table not found", code: 404 };
13
- }
14
-
15
- const crudInc = await rclient.get(`pg:${config.pg?.database}:admin.properties:crud`) || 0;
16
- const cacheKey = [config.pg?.database, "cms:settings", crudInc, entity, keys, uid].filter(Boolean).join(":");
17
- const cache = ttl === 0 ? null : await rclient.get(cacheKey);
18
-
19
- // return from cache
20
- if (cache) {
21
- return { cache: true, ...JSON.parse(cache) };
22
- }
23
-
24
- const rows = await pg.query(
25
- "select property_key as key, property_text, property_json from admin.properties where property_entity=$1",
26
- entity === "user" ? [uid] : [entity || "app"]
27
- ).then(el => el.rows || []);
28
-
29
- const settings = rows
30
- .filter((row) =>
31
- typeof keys === "string" ? keys.includes(row.key) : true
32
- )
33
- .reduce(
34
- (
35
- acc,
36
- { key, property_text, property_json }
37
- ) => ({
38
- ...acc,
39
- [key]: property_text || property_json,
40
- }),
41
- {}
42
- );
43
-
44
- // save to cache, default = 1 hour
45
- if (ttl) await rclient.set(cacheKey, JSON.stringify(settings), 'EX', ttl);
46
-
47
- return settings;
48
- }
1
+ import { config, pgClients, getRedis } from "@opengis/fastify-table/utils.js";
2
+
3
+ const pg = pgClients.client;
4
+ const rclient = getRedis();
5
+
6
+ export default async function getSettings({ entity = 'app', keys = ['cms'], uid = 0, ttl = 3600 } = {}) {
7
+ if (!pg) {
8
+ return { error: "empty pg", code: 500 };
9
+ }
10
+
11
+ if (!pg.pk?.["admin.properties"]) {
12
+ return { error: "properties table not found", code: 404 };
13
+ }
14
+
15
+ const crudInc = await rclient.get(`pg:${config.pg?.database}:admin.properties:crud`) || 0;
16
+ const cacheKey = [config.pg?.database, "cms:settings", crudInc, entity, keys, uid].filter(Boolean).join(":");
17
+ const cache = ttl === 0 ? null : await rclient.get(cacheKey);
18
+
19
+ // return from cache
20
+ if (cache) {
21
+ return { cache: true, ...JSON.parse(cache) };
22
+ }
23
+
24
+ const rows = await pg.query(
25
+ "select property_key as key, property_text, property_json from admin.properties where property_entity=$1",
26
+ entity === "user" ? [uid] : [entity || "app"]
27
+ ).then(el => el.rows || []);
28
+
29
+ const settings = rows
30
+ .filter((row) =>
31
+ typeof keys === "string" ? keys.includes(row.key) : true
32
+ )
33
+ .reduce(
34
+ (
35
+ acc,
36
+ { key, property_text, property_json }
37
+ ) => ({
38
+ ...acc,
39
+ [key]: property_text || property_json,
40
+ }),
41
+ {}
42
+ );
43
+
44
+ // save to cache, default = 1 hour
45
+ if (ttl) await rclient.set(cacheKey, JSON.stringify(settings), 'EX', ttl);
46
+
47
+ return settings;
48
+ }
@@ -1,112 +1,112 @@
1
- // perimissions
2
- import getPermissions from './controllers/getPermissions.js';
3
- import setPermissions from './controllers/setPermissions.js';
4
-
5
- // media
6
- import listMedia from './controllers/listMedia.js';
7
- import metadata from './controllers/metadataMedia.js';
8
- import uploadMedia from './controllers/uploadMedia.js';
9
- import del from './controllers/deleteMedia.js';
10
- import download from './controllers/downloadMedia.js';
11
-
12
- // content
13
- import getContent from './controllers/getContent.js';
14
- import getContentBySlug from './controllers/getContentBySlug.js';
15
- import insertContent from './controllers/insertContent.js';
16
- import updateContent from './controllers/updateContent.js';
17
- import deleteContent from './controllers/deleteContent.js';
18
- import { translateContent, translateCollection } from './controllers/translate.js';
19
-
20
- // suggest
21
- import cmsSuggest from './controllers/cmsSuggest.js';
22
-
23
- // statistics
24
- import cmsStat from './controllers/cmsStat.js';
25
- import searchContent from './controllers/searchContent.js';
26
-
27
- import getAppSettings from "./controllers/properties.get.js";
28
- import postAppSettings from "./controllers/properties.post.js";
29
-
30
- const suggestSchema = {
31
- querystring: {
32
- type: 'object',
33
- properties: {
34
- search: { type: 'string' },
35
- filter: { type: 'string' },
36
- limit: { type: 'number', exclusiveMinimum: 0 },
37
- },
38
- },
39
- };
40
-
41
- const propertiesSchema = {
42
- type: "object",
43
- properties: {
44
- params: {
45
- id: { type: "string", pattern: "^([\\d\\w]+)$" },
46
- key: { type: "string", pattern: "^([\\d\\w._]+)$" },
47
- },
48
- querystring: {
49
- json: { type: "string", pattern: "^([\\d\\w]+)$" },
50
- },
51
- },
52
- };
53
-
54
- const translateContentSchema = {
55
- type: "object",
56
- properties: {
57
- params: {
58
- id: {
59
- type: "string"
60
- },
61
- },
62
- querystring: {
63
- required: ['to'],
64
- additionalProperties: false,
65
- from: {
66
- type: "string"
67
- },
68
- to: {
69
- type: "string"
70
- },
71
- },
72
- },
73
- };
74
-
75
- const params = { config: { policy: 'L0' } };
76
-
77
- export default function route(app) {
78
- app.post('/cms-permissions/:id', { config: { role: 'admin' } }, setPermissions);
79
- app.get('/cms-permissions/:id?', params, getPermissions);
80
- app.get('/cms-translate', { config: { role: "admin" }, schema: translateContentSchema }, translateContent);
81
- app.get('/cms-translate-collection/:id', { config: { role: "admin" }, schema: translateContentSchema }, translateCollection);
82
-
83
- app.post('/cms-media/upload', params, uploadMedia);
84
- app.get('/cms-media', params, listMedia);
85
- app.get('/cms-media/:id/:type', params, download);
86
- app.get('/cms-media/:id', params, metadata);
87
- app.delete('/cms-media/:id?', params, del); // media file with id / subdir without
88
- app.get('/cms-media/:id/delete', params, del); // debug
89
-
90
- // Bearer token required
91
- app.get('/cms-content/:slug/:lang?', params, getContentBySlug);
92
- app.get('/cms-search', params, searchContent);
93
- app.get('/cms/:type', params, getContent);
94
- app.get('/cms/:type/:id/:lang?', params, getContent);
95
-
96
- app.post('/cms/:type/:id?', params, insertContent);
97
- app.put('/cms/:type/:id?', params, updateContent);
98
- app.delete('/cms/:type/:id', params, deleteContent);
99
-
100
- app.get('/cms-suggest/:id', { ...params, schema: suggestSchema }, cmsSuggest);
101
- app.get('/cms-stat', params, cmsStat);
102
- app.get(
103
- "/settings",
104
- { config: { policy: "L0" }, schema: propertiesSchema },
105
- getAppSettings
106
- );
107
- app.post(
108
- "/settings",
109
- { config: { policy: "L0" } },
110
- postAppSettings
111
- );
112
- }
1
+ // perimissions
2
+ import getPermissions from './controllers/getPermissions.js';
3
+ import setPermissions from './controllers/setPermissions.js';
4
+
5
+ // media
6
+ import listMedia from './controllers/listMedia.js';
7
+ import metadata from './controllers/metadataMedia.js';
8
+ import uploadMedia from './controllers/uploadMedia.js';
9
+ import del from './controllers/deleteMedia.js';
10
+ import download from './controllers/downloadMedia.js';
11
+
12
+ // content
13
+ import getContent from './controllers/getContent.js';
14
+ import getContentBySlug from './controllers/getContentBySlug.js';
15
+ import insertContent from './controllers/insertContent.js';
16
+ import updateContent from './controllers/updateContent.js';
17
+ import deleteContent from './controllers/deleteContent.js';
18
+ import { translateContent, translateCollection } from './controllers/translate.js';
19
+
20
+ // suggest
21
+ import cmsSuggest from './controllers/cmsSuggest.js';
22
+
23
+ // statistics
24
+ import cmsStat from './controllers/cmsStat.js';
25
+ import searchContent from './controllers/searchContent.js';
26
+
27
+ import getAppSettings from "./controllers/properties.get.js";
28
+ import postAppSettings from "./controllers/properties.post.js";
29
+
30
+ const suggestSchema = {
31
+ querystring: {
32
+ type: 'object',
33
+ properties: {
34
+ search: { type: 'string' },
35
+ filter: { type: 'string' },
36
+ limit: { type: 'number', exclusiveMinimum: 0 },
37
+ },
38
+ },
39
+ };
40
+
41
+ const propertiesSchema = {
42
+ type: "object",
43
+ properties: {
44
+ params: {
45
+ id: { type: "string", pattern: "^([\\d\\w]+)$" },
46
+ key: { type: "string", pattern: "^([\\d\\w._]+)$" },
47
+ },
48
+ querystring: {
49
+ json: { type: "string", pattern: "^([\\d\\w]+)$" },
50
+ },
51
+ },
52
+ };
53
+
54
+ const translateContentSchema = {
55
+ type: "object",
56
+ properties: {
57
+ params: {
58
+ id: {
59
+ type: "string"
60
+ },
61
+ },
62
+ querystring: {
63
+ required: ['to'],
64
+ additionalProperties: false,
65
+ from: {
66
+ type: "string"
67
+ },
68
+ to: {
69
+ type: "string"
70
+ },
71
+ },
72
+ },
73
+ };
74
+
75
+ const params = { config: { policy: 'L0' } };
76
+
77
+ export default function route(app) {
78
+ app.post('/cms-permissions/:id', { config: { role: 'admin' } }, setPermissions);
79
+ app.get('/cms-permissions/:id?', params, getPermissions);
80
+ app.get('/cms-translate', { config: { role: "admin" }, schema: translateContentSchema }, translateContent);
81
+ app.get('/cms-translate-collection/:id', { config: { role: "admin" }, schema: translateContentSchema }, translateCollection);
82
+
83
+ app.post('/cms-media/upload', params, uploadMedia);
84
+ app.get('/cms-media', params, listMedia);
85
+ app.get('/cms-media/:id/:type', params, download);
86
+ app.get('/cms-media/:id', params, metadata);
87
+ app.delete('/cms-media/:id?', params, del); // media file with id / subdir without
88
+ app.get('/cms-media/:id/delete', params, del); // debug
89
+
90
+ // Bearer token required
91
+ app.get('/cms-content/:slug/:lang?', params, getContentBySlug);
92
+ app.get('/cms-search', params, searchContent);
93
+ app.get('/cms/:type', params, getContent);
94
+ app.get('/cms/:type/:id/:lang?', params, getContent);
95
+
96
+ app.post('/cms/:type/:id?', params, insertContent);
97
+ app.put('/cms/:type/:id?', params, updateContent);
98
+ app.delete('/cms/:type/:id', params, deleteContent);
99
+
100
+ app.get('/cms-suggest/:id', { ...params, schema: suggestSchema }, cmsSuggest);
101
+ app.get('/cms-stat', params, cmsStat);
102
+ app.get(
103
+ "/settings",
104
+ { config: { policy: "L0" }, schema: propertiesSchema },
105
+ getAppSettings
106
+ );
107
+ app.post(
108
+ "/settings",
109
+ { config: { policy: "L0" } },
110
+ postAppSettings
111
+ );
112
+ }
@@ -1,36 +1,36 @@
1
- export default async function additionalData(pg, rows, locale, fields = '*') {
2
- const { rows: localizations = [] } = await pg.query(`select json_object_agg(field_key, field_value), object_id from site.localization
3
- where object_id=any($1) and ${locale && locale !== 'uk' ? 'REVERSE(split_part(REVERSE(field_key), \':\', 1)) = $2' : '1=1'} group by object_id`, [rows.map(el => el.id), locale && locale !== 'uk' ? locale : null].filter(Boolean));
4
-
5
- const { rows: tagsList = [] } = await pg.query(`
6
- SELECT
7
- td.data_id,
8
- json_agg(
9
- json_build_object('id', t.tag_id, 'text', t.value, 'color', t.color, 'slug', t.slug, 'locale', t.locale)
10
- ) AS tag
11
- FROM site.tag_data td
12
- JOIN site.tags t ON t.tag_id = td.tag_id
13
- where data_id=any($1)
14
- GROUP BY td.data_id;
15
- `, [rows.map(el => el.id)]);
16
-
17
- rows.forEach(row => {
18
- if (locale && locale !== 'uk' && row.meta && Object.keys(row.meta || {}).find(key => key.split(':').pop() === locale)) {
19
- row.meta = Object.fromEntries(Object.keys(row.meta || {}).filter(key => key.split(':').pop() === locale && row.meta?.[key]).map(key => [key.split(':').shift(), row.meta[key]]));
20
- }
21
-
22
- const localization = localizations.find(el => el.object_id === row.id);
23
- const localizationKeys = Object.keys(localization?.json_object_agg || {}).filter(key => row[key.split(':').shift()]);
24
- const localizationObj1 = Object.entries(localization?.json_object_agg || {}).filter(([key]) => rows.length > 1 ? true : localizationKeys.includes(key)).reduce((acc, curr) => ({ ...acc, [curr[0]]: typeof curr[1] === 'string' && curr[1].startsWith('[') && curr[1].endsWith(']') ? JSON.parse(curr[1]) : curr[1] }), {});
25
- const localizationObj = fields?.length && fields !== '*' ? Object.fromEntries(Object.entries(localizationObj1).filter(([key]) => fields.split(',').includes(key.split(':').shift()))) : localizationObj1;
26
- if (locale && locale !== 'uk') {
27
- Object.assign(row, Object.keys(localizationObj).reduce((acc, curr) => ({ ...acc, [curr.replace(`:${locale}`, '')]: localizationObj[curr] }), {}));
28
- } else if (!locale) {
29
- Object.assign(row, localizationObj);
30
- }
31
-
32
- const { tag = [] } = tagsList.find(el => el?.data_id === row?.id) || {};
33
- const localizedTags = locale ? tag.map(el => ({ ...el, text: el.locale?.[locale] || el.text })) : tag;
34
- Object.assign(row, { tag_list: localizedTags });
35
- });
1
+ export default async function additionalData(pg, rows, locale, fields = '*') {
2
+ const { rows: localizations = [] } = await pg.query(`select json_object_agg(field_key, field_value), object_id from site.localization
3
+ where object_id=any($1) and ${locale && locale !== 'uk' ? 'REVERSE(split_part(REVERSE(field_key), \':\', 1)) = $2' : '1=1'} group by object_id`, [rows.map(el => el.id), locale && locale !== 'uk' ? locale : null].filter(Boolean));
4
+
5
+ const { rows: tagsList = [] } = await pg.query(`
6
+ SELECT
7
+ td.data_id,
8
+ json_agg(
9
+ json_build_object('id', t.tag_id, 'text', t.value, 'color', t.color, 'slug', t.slug, 'locale', t.locale)
10
+ ) AS tag
11
+ FROM site.tag_data td
12
+ JOIN site.tags t ON t.tag_id = td.tag_id
13
+ where data_id=any($1)
14
+ GROUP BY td.data_id;
15
+ `, [rows.map(el => el.id)]);
16
+
17
+ rows.forEach(row => {
18
+ if (locale && locale !== 'uk' && row.meta && Object.keys(row.meta || {}).find(key => key.split(':').pop() === locale)) {
19
+ row.meta = Object.fromEntries(Object.keys(row.meta || {}).filter(key => key.split(':').pop() === locale && row.meta?.[key]).map(key => [key.split(':').shift(), row.meta[key]]));
20
+ }
21
+
22
+ const localization = localizations.find(el => el.object_id === row.id);
23
+ const localizationKeys = Object.keys(localization?.json_object_agg || {}).filter(key => row[key.split(':').shift()]);
24
+ const localizationObj1 = Object.entries(localization?.json_object_agg || {}).filter(([key]) => rows.length > 1 ? true : localizationKeys.includes(key)).reduce((acc, curr) => ({ ...acc, [curr[0]]: typeof curr[1] === 'string' && curr[1].startsWith('[') && curr[1].endsWith(']') ? JSON.parse(curr[1]) : curr[1] }), {});
25
+ const localizationObj = fields?.length && fields !== '*' ? Object.fromEntries(Object.entries(localizationObj1).filter(([key]) => fields.split(',').includes(key.split(':').shift()))) : localizationObj1;
26
+ if (locale && locale !== 'uk') {
27
+ Object.assign(row, Object.keys(localizationObj).reduce((acc, curr) => ({ ...acc, [curr.replace(`:${locale}`, '')]: localizationObj[curr] }), {}));
28
+ } else if (!locale) {
29
+ Object.assign(row, localizationObj);
30
+ }
31
+
32
+ const { tag = [] } = tagsList.find(el => el?.data_id === row?.id) || {};
33
+ const localizedTags = locale ? tag.map(el => ({ ...el, text: el.locale?.[locale] || el.text })) : tag;
34
+ Object.assign(row, { tag_list: localizedTags });
35
+ });
36
36
  }
@@ -1,90 +1,90 @@
1
- import { pgClients, getData, getMeta } from "@opengis/fastify-table/utils.js";
2
-
3
- import additionalData from "./additionalData.js";
4
-
5
- export default async function getCollection({
6
- table, id, limit, maxLimit, order, search, tags, filter, state, page, desc, sql, locale, contextQuery, statusQuery, columns, preview, user, defaultColumns, fields, defaultFields = [], defaultFilters = [], called = false,
7
- }, reply, pg = pgClients.client) {
8
- const meta = table ? await getMeta({ pg, table: 'data.' + table }) : {};
9
-
10
- if (!table || !meta?.pk) {
11
- return { message: 'content table not found', status: 404 };
12
- }
13
-
14
- const isPinExists = await pg.query(`
15
- SELECT 1
16
- FROM pg_catalog.pg_attribute a
17
- JOIN pg_catalog.pg_class c ON a.attrelid = c.oid
18
- JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid
19
- WHERE n.nspname = 'data'
20
- AND c.relname = $1
21
- AND a.attname = 'is_pin'
22
- AND a.attnum > 0
23
- AND NOT a.attisdropped;
24
- `, [table]).then(el => el.rowCount);
25
-
26
- const defaultOrder = `case when status='archived' then true else false end ${isPinExists ? ', is_pin desc' : ''}, published_at desc nulls last`;
27
-
28
- const localeQuery = locale && locale !== 'uk' ? `id in ( select object_id from site.localization where REVERSE(split_part(REVERSE(field_key), ':', 1)) = '${locale.replace(/'/g, "''")}' )` : undefined;
29
- const tagQuery = tags ? `id in (SELECT data_id FROM site.tag_data td left join site.tags ts on td.tag_id=ts.tag_id WHERE ts.slug = any('{ ${tags.replace(/'/g, "''")} }'::text[]) or ts.tag_id = any('{ ${tags.replace(/'/g, "''")} }'::text[]))` : null;
30
- const cQuery = [id ? `'${id}' in (id,slug)` : contextQuery, localeQuery, ((columns || []).concat(defaultColumns || [])).find(col => col.name === 'status') ? statusQuery : null, tagQuery].filter(Boolean).join(' and ');
31
-
32
- const columnList = await getMeta({
33
- pg,
34
- table: 'data.' + `"${table}"`
35
- }).then(el => el.columns?.map?.(col => col.name) || []);
36
- const existingFields = fields && !id ? defaultFields.concat((fields || '').split(',')).filter(colName => columnList.includes(colName)).join(',') : null;
37
-
38
- const filterList = defaultFilters.concat(columns.map(col => ({ name: col.name, type: col.type && ['date', 'datetime'].includes(col.type) ? 'Date' : 'Text', label: col.label, sql: col.sql })));
39
-
40
- const res = await getData({
41
- pg,
42
- table: 'data.' + `"${table}"`,
43
- columns: existingFields,
44
- filterList,
45
- query: {
46
- filter,
47
- state,
48
- limit: Math.min(limit, maxLimit),
49
- page,
50
- search,
51
- order: order ? order : defaultOrder,
52
- desc,
53
- sql
54
- },
55
- user,
56
- contextQuery: cQuery,
57
- actions: ['view']
58
- }, reply, true);
59
-
60
- const locales = await pg.query(`select array_agg(distinct REVERSE(split_part(REVERSE(field_key), ':', 1))) from site.localization where object_id in (select id from ${'data.' + `"${table}"`})`).then(el => el.rows?.[0]?.array_agg || []);
61
-
62
- // Apply localization and tags etc.
63
- if (res?.rows?.length) {
64
- await additionalData(pg, res.rows, locale, id ? null : existingFields);
65
- }
66
-
67
- const columns1 = !id
68
- ? columns?.map(col => Object.assign(col, { type: col.name === 'published_at' ? 'date' : col.type }))?.filter?.(el => !el.hidden)
69
- : columns?.filter?.(el => !el.hidden);
70
-
71
- const finalColumns = (defaultColumns || []).concat(columns1.filter(col => defaultColumns.findIndex(el => el.name === col.name) === -1));
72
-
73
- finalColumns.filter(el => el.defaultColumn).forEach(col => {
74
- const { name, localization } = columns1.find(item => item.name === col.name) || {};
75
- if (name) {
76
- Object.assign(col, { localization });
77
- }
78
- });
79
-
80
- if (res?.columns) {
81
- Object.assign(res, { type: 'collection', locales, preview_path: preview, columns: finalColumns });
82
- }
83
-
84
- // add table name for cache via getContent function
85
- if (called) {
86
- Object.assign(res, { table: 'data.' + `"${table}"` });
87
- }
88
-
89
- return res;
1
+ import { pgClients, getData, getMeta } from "@opengis/fastify-table/utils.js";
2
+
3
+ import additionalData from "./additionalData.js";
4
+
5
+ export default async function getCollection({
6
+ table, id, limit, maxLimit, order, search, tags, filter, state, page, desc, sql, locale, contextQuery, statusQuery, columns, preview, user, defaultColumns, fields, defaultFields = [], defaultFilters = [], called = false,
7
+ }, reply, pg = pgClients.client) {
8
+ const meta = table ? await getMeta({ pg, table: 'data.' + table }) : {};
9
+
10
+ if (!table || !meta?.pk) {
11
+ return { message: 'content table not found', status: 404 };
12
+ }
13
+
14
+ const isPinExists = await pg.query(`
15
+ SELECT 1
16
+ FROM pg_catalog.pg_attribute a
17
+ JOIN pg_catalog.pg_class c ON a.attrelid = c.oid
18
+ JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid
19
+ WHERE n.nspname = 'data'
20
+ AND c.relname = $1
21
+ AND a.attname = 'is_pin'
22
+ AND a.attnum > 0
23
+ AND NOT a.attisdropped;
24
+ `, [table]).then(el => el.rowCount);
25
+
26
+ const defaultOrder = `case when status='archived' then true else false end ${isPinExists ? ', is_pin desc' : ''}, published_at desc nulls last`;
27
+
28
+ const localeQuery = locale && locale !== 'uk' ? `id in ( select object_id from site.localization where REVERSE(split_part(REVERSE(field_key), ':', 1)) = '${locale.replace(/'/g, "''")}' )` : undefined;
29
+ const tagQuery = tags ? `id in (SELECT data_id FROM site.tag_data td left join site.tags ts on td.tag_id=ts.tag_id WHERE ts.slug = any('{ ${tags.replace(/'/g, "''")} }'::text[]) or ts.tag_id = any('{ ${tags.replace(/'/g, "''")} }'::text[]))` : null;
30
+ const cQuery = [id ? `'${id}' in (id,slug)` : contextQuery, localeQuery, ((columns || []).concat(defaultColumns || [])).find(col => col.name === 'status') ? statusQuery : null, tagQuery].filter(Boolean).join(' and ');
31
+
32
+ const columnList = await getMeta({
33
+ pg,
34
+ table: 'data.' + `"${table}"`
35
+ }).then(el => el.columns?.map?.(col => col.name) || []);
36
+ const existingFields = fields && !id ? defaultFields.concat((fields || '').split(',')).filter(colName => columnList.includes(colName)).join(',') : null;
37
+
38
+ const filterList = defaultFilters.concat(columns.map(col => ({ name: col.name, type: col.type && ['date', 'datetime'].includes(col.type) ? 'Date' : 'Text', label: col.label, sql: col.sql })));
39
+
40
+ const res = await getData({
41
+ pg,
42
+ table: 'data.' + `"${table}"`,
43
+ columns: existingFields,
44
+ filterList,
45
+ query: {
46
+ filter,
47
+ state,
48
+ limit: Math.min(limit, maxLimit),
49
+ page,
50
+ search,
51
+ order: order ? order : defaultOrder,
52
+ desc,
53
+ sql
54
+ },
55
+ user,
56
+ contextQuery: cQuery,
57
+ actions: ['view']
58
+ }, reply, true);
59
+
60
+ const locales = await pg.query(`select array_agg(distinct REVERSE(split_part(REVERSE(field_key), ':', 1))) from site.localization where object_id in (select id from ${'data.' + `"${table}"`})`).then(el => el.rows?.[0]?.array_agg || []);
61
+
62
+ // Apply localization and tags etc.
63
+ if (res?.rows?.length) {
64
+ await additionalData(pg, res.rows, locale, id ? null : existingFields);
65
+ }
66
+
67
+ const columns1 = !id
68
+ ? columns?.map(col => Object.assign(col, { type: col.name === 'published_at' ? 'date' : col.type }))?.filter?.(el => !el.hidden)
69
+ : columns?.filter?.(el => !el.hidden);
70
+
71
+ const finalColumns = (defaultColumns || []).concat(columns1.filter(col => defaultColumns.findIndex(el => el.name === col.name) === -1));
72
+
73
+ finalColumns.filter(el => el.defaultColumn).forEach(col => {
74
+ const { name, localization } = columns1.find(item => item.name === col.name) || {};
75
+ if (name) {
76
+ Object.assign(col, { localization });
77
+ }
78
+ });
79
+
80
+ if (res?.columns) {
81
+ Object.assign(res, { type: 'collection', locales, preview_path: preview, columns: finalColumns });
82
+ }
83
+
84
+ // add table name for cache via getContent function
85
+ if (called) {
86
+ Object.assign(res, { table: 'data.' + `"${table}"` });
87
+ }
88
+
89
+ return res;
90
90
  }