@opengis/cms 0.0.58 → 0.0.60
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.
- package/README.md +131 -131
- package/dist/{ArticlesPage-CFjE_cw_.js → ArticlesPage-BjYzvTWM.js} +3 -3
- package/dist/{CollectionsBreadcrumb-BCxeRikP.js → CollectionsBreadcrumb-HePNJb-d.js} +1 -1
- package/dist/CollectionsBreadcrumb.vue_vue_type_script_setup_true_lang-BJh-tjam.js +53 -0
- package/dist/{Dashboard-C1eGscNd.js → Dashboard-CXkg_pk8.js} +132 -132
- package/dist/EditCollectionPage-BycuD920.js +188 -0
- package/dist/{MenuAddPage-D-p3gFgm.js → MenuAddPage-QTnwCoGh.js} +1 -1
- package/dist/{MenuBody-rN5j4YBu.js → MenuBody-Bi0ONVZf.js} +2 -2
- package/dist/{MenuItemPage-BoJw885D.js → MenuItemPage-B7Y9KFyb.js} +3 -3
- package/dist/{MenuList-DFEBS0NB.js → MenuList-BLIpeqSd.js} +53 -53
- package/dist/{MenuPage-BCZB_S8j.js → MenuPage-3W6jZ15H.js} +1 -1
- package/dist/{MenuWrapper-AZ_8s-zd.js → MenuWrapper-OrOv6sOb.js} +1 -1
- package/dist/{MonacoEditor-Db-3Jc3E.js → MonacoEditor-ByPT8pnv.js} +1 -1
- package/dist/MonacoEditor.vue_vue_type_script_setup_true_lang-C8cip9Ci.js +84 -0
- package/dist/{UniversalTable-CzqPG-tY.js → UniversalTable-GBd_pStq.js} +80 -80
- package/dist/{UniversalTablePagination-4gL47A7I.js → UniversalTablePagination-Dw2hc0nc.js} +46 -46
- package/dist/{contentForm-CtMhQTG0.js → contentForm-yMn63kza.js} +48 -48
- package/dist/index.js +5 -5
- package/dist/{vs-builder-monaco-B3Jj0V31.js → vs-builder-monaco-Cw-f19gc.js} +1 -1
- package/input-types.json +9 -9
- package/locales/en.json +815 -815
- package/locales/uk.json +813 -813
- package/module/cms/cls/content.status.json +17 -17
- package/module/cms/cls/user_type.json +9 -9
- package/module/cms/form/admin.users.form.json +77 -77
- package/module/cms/select/cms.page_type.sql +1 -1
- package/module/cms/select/news_tag_id.sql +11 -11
- package/module/cms/table/admin.users.table.json +53 -53
- package/module/cms/table/collection.default.table.json +96 -96
- package/module/cms/table/single.default.table.json +116 -116
- package/package.json +2 -1
- package/plugin.js +43 -43
- package/server/app.js +35 -35
- package/server/config.js +4 -4
- package/server/functions/getContent.js +45 -45
- package/server/functions/getDraftKey.js +22 -22
- package/server/functions/getSearchData.js +31 -31
- package/server/functions/getTags.js +30 -30
- package/server/functions/getUser.js +27 -27
- package/server/functions/utils/mock.reply.js +55 -55
- package/server/index.js +22 -22
- package/server/migrations/fixes.sql +129 -129
- package/server/migrations/site.sql +595 -595
- package/server/plugins/adminHook.js +78 -78
- package/server/plugins/hook.js +59 -59
- package/server/plugins/vite.js +75 -75
- package/server/routes/category/controllers/cms.category.delete.js +21 -21
- package/server/routes/category/controllers/cms.category.get.js +17 -17
- package/server/routes/category/controllers/cms.category.list.js +16 -16
- package/server/routes/category/controllers/cms.category.post.js +21 -21
- package/server/routes/category/controllers/cms.category.put.js +23 -23
- package/server/routes/category/index.mjs +22 -22
- package/server/routes/cms/controllers/cmsStat.js +55 -55
- package/server/routes/cms/controllers/cmsSuggest.js +57 -57
- package/server/routes/cms/controllers/deleteContent.js +113 -113
- package/server/routes/cms/controllers/deleteMedia.js +76 -76
- package/server/routes/cms/controllers/downloadMedia.js +84 -84
- package/server/routes/cms/controllers/getContent.js +113 -113
- package/server/routes/cms/controllers/getContentBySlug.js +93 -93
- package/server/routes/cms/controllers/getPermissions.js +15 -15
- package/server/routes/cms/controllers/insertContent.js +217 -217
- package/server/routes/cms/controllers/listMedia.js +155 -155
- package/server/routes/cms/controllers/metadataMedia.js +39 -39
- package/server/routes/cms/controllers/properties.get.js +18 -18
- package/server/routes/cms/controllers/properties.post.js +99 -99
- package/server/routes/cms/controllers/searchContent.js +214 -214
- package/server/routes/cms/controllers/setPermissions.js +49 -49
- package/server/routes/cms/controllers/translate.js +89 -89
- package/server/routes/cms/controllers/updateContent.js +266 -266
- package/server/routes/cms/controllers/uploadMedia.js +79 -79
- package/server/routes/cms/functions/getSettings.js +48 -48
- package/server/routes/cms/index.mjs +112 -112
- package/server/routes/cms/utils/additionalData.js +35 -35
- package/server/routes/cms/utils/getCollection.js +89 -89
- package/server/routes/cms/utils/getSingle.js +188 -188
- package/server/routes/cms/utils/inputTypes.js +5 -5
- package/server/routes/cms/utils/insertContentLocalization.js +104 -104
- package/server/routes/cms/utils/requestTranslation.js +113 -85
- package/server/routes/cms/utils/updateLocalization.js +47 -47
- package/server/routes/cmsSpace/controllers/deleteSpace.js +25 -25
- package/server/routes/cmsSpace/controllers/getSpaces.js +27 -27
- package/server/routes/cmsSpace/controllers/insertSpace.js +21 -21
- package/server/routes/cmsSpace/controllers/updateSpace.js +23 -23
- package/server/routes/cmsSpace/index.mjs +20 -20
- package/server/routes/contentType/controllers/addContentType.js +160 -160
- package/server/routes/contentType/controllers/contentTypeList.js +54 -54
- package/server/routes/contentType/controllers/delContentType.js +75 -75
- package/server/routes/contentType/controllers/editContentType.js +88 -88
- package/server/routes/contentType/controllers/getContentType.js +65 -65
- package/server/routes/contentType/index.mjs +35 -35
- package/server/routes/contentType/utils/updateContents.js +44 -44
- package/server/routes/contentType/utils/updateCustomContentTable.js +53 -53
- package/server/routes/feedback/controllers/email.list.js +24 -24
- package/server/routes/feedback/controllers/feedback.js +48 -48
- package/server/routes/feedback/controllers/feedback.list.js +37 -37
- package/server/routes/feedback/controllers/news.subscriptions.js +44 -44
- package/server/routes/feedback/index.mjs +71 -71
- package/server/routes/logs/controllers/export.user.logs.js +77 -77
- package/server/routes/logs/controllers/user.logs.js +44 -44
- package/server/routes/logs/index.mjs +9 -9
- package/server/routes/menu/controllers/addMenu.js +37 -37
- package/server/routes/menu/controllers/delMenu.js +31 -31
- package/server/routes/menu/controllers/editMenu.js +41 -41
- package/server/routes/menu/controllers/getMenu.js +24 -24
- package/server/routes/menu/functions/getMenu.js +50 -50
- package/server/routes/menu/index.mjs +13 -13
- package/server/routes/migration/controllers/collectionToCustom.js +137 -137
- package/server/routes/migration/index.mjs +8 -8
- package/server/routes/root.mjs +8 -8
- package/server/routes/tags/controllers/add.tags.js +24 -24
- package/server/routes/tags/controllers/del.tags.js +19 -19
- package/server/routes/tags/controllers/edit.tags.js +25 -25
- package/server/routes/tags/controllers/get.tags.js +15 -15
- package/server/routes/tags/index.mjs +14 -14
- package/server/templates/cls/cms.category_type.json +9 -9
- package/server/templates/cls/cms.content_review_status.json +9 -9
- package/server/templates/cls/cms.content_status.json +9 -9
- package/server/templates/cls/cms.content_type.json +9 -9
- package/server/templates/cls/cms.lang.json +9 -9
- package/server/templates/page/login.html +126 -126
- package/server/templates/select/core.user_mentioned.sql +1 -1
- package/utils.d.ts +52 -52
- package/utils.js +8 -8
- package/dist/CollectionsBreadcrumb.vue_vue_type_script_setup_true_lang-umRzB5mY.js +0 -53
- package/dist/EditCollectionPage-DIr1tdtn.js +0 -187
- package/dist/MonacoEditor.vue_vue_type_script_setup_true_lang-B1DrxmQX.js +0 -84
- package/dist/images/logo.png +0 -0
- package/dist/index.html +0 -29
- package/dist/vite.svg +0 -1
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import { dataInsert, pgClients } from '@opengis/fastify-table/utils.js';
|
|
2
|
-
|
|
3
|
-
export default async function insertSpace({ pg = pgClients.client, user, params, headers = {}, body = {} }, reply) {
|
|
4
|
-
if (!pg?.pk) { return reply.status(400).send('empty pg'); }
|
|
5
|
-
if (!pg?.pk?.['site.spaces']) { return reply.status(400).send('table not found: site.spaces'); }
|
|
6
|
-
|
|
7
|
-
const exists = params?.id ? await pg.query('select space_id from site.spaces where space_id=$1', [params.id]).then(el => el.rows?.[0]?.space_id) : false;
|
|
8
|
-
if (exists) { return reply.status(400).send('space aleady exists: ' + params?.id); }
|
|
9
|
-
|
|
10
|
-
const { referer } = headers;
|
|
11
|
-
|
|
12
|
-
const res = await dataInsert({
|
|
13
|
-
pg,
|
|
14
|
-
table: 'site.spaces',
|
|
15
|
-
data: body,
|
|
16
|
-
id: params?.id,
|
|
17
|
-
uid: user?.uid,
|
|
18
|
-
referer,
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
return { id: res?.rows?.[0]?.space_id, rows: res?.rows || [] };
|
|
1
|
+
import { dataInsert, pgClients } from '@opengis/fastify-table/utils.js';
|
|
2
|
+
|
|
3
|
+
export default async function insertSpace({ pg = pgClients.client, user, params, headers = {}, body = {} }, reply) {
|
|
4
|
+
if (!pg?.pk) { return reply.status(400).send('empty pg'); }
|
|
5
|
+
if (!pg?.pk?.['site.spaces']) { return reply.status(400).send('table not found: site.spaces'); }
|
|
6
|
+
|
|
7
|
+
const exists = params?.id ? await pg.query('select space_id from site.spaces where space_id=$1', [params.id]).then(el => el.rows?.[0]?.space_id) : false;
|
|
8
|
+
if (exists) { return reply.status(400).send('space aleady exists: ' + params?.id); }
|
|
9
|
+
|
|
10
|
+
const { referer } = headers;
|
|
11
|
+
|
|
12
|
+
const res = await dataInsert({
|
|
13
|
+
pg,
|
|
14
|
+
table: 'site.spaces',
|
|
15
|
+
data: body,
|
|
16
|
+
id: params?.id,
|
|
17
|
+
uid: user?.uid,
|
|
18
|
+
referer,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
return { id: res?.rows?.[0]?.space_id, rows: res?.rows || [] };
|
|
22
22
|
}
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
import { dataUpdate, pgClients } from '@opengis/fastify-table/utils.js';
|
|
2
|
-
|
|
3
|
-
export default async function updateSpace({ pg = pgClients.client, user, params, headers = {}, body = {} }, reply) {
|
|
4
|
-
// if (!params?.id) { return reply.status(400).send('not enough params: id'); }
|
|
5
|
-
if (!pg?.pk) { return reply.status(400).send('empty pg'); }
|
|
6
|
-
if (!pg?.pk?.['site.spaces']) { return reply.status(400).send('table not found: site.spaces'); }
|
|
7
|
-
|
|
8
|
-
const id = 'default';
|
|
9
|
-
const exists = await pg.query('select space_id from site.spaces where space_id=$1', [id]).then(el => el.rows?.[0]?.space_id);
|
|
10
|
-
if (!exists) { return reply.status(404).send('space not found: ' + id); }
|
|
11
|
-
|
|
12
|
-
const { referer } = headers;
|
|
13
|
-
|
|
14
|
-
const res = await dataUpdate({
|
|
15
|
-
pg,
|
|
16
|
-
table: 'site.spaces',
|
|
17
|
-
data: body,
|
|
18
|
-
id,
|
|
19
|
-
uid: user?.uid,
|
|
20
|
-
referer,
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
return { id, ...res || {} };
|
|
1
|
+
import { dataUpdate, pgClients } from '@opengis/fastify-table/utils.js';
|
|
2
|
+
|
|
3
|
+
export default async function updateSpace({ pg = pgClients.client, user, params, headers = {}, body = {} }, reply) {
|
|
4
|
+
// if (!params?.id) { return reply.status(400).send('not enough params: id'); }
|
|
5
|
+
if (!pg?.pk) { return reply.status(400).send('empty pg'); }
|
|
6
|
+
if (!pg?.pk?.['site.spaces']) { return reply.status(400).send('table not found: site.spaces'); }
|
|
7
|
+
|
|
8
|
+
const id = 'default';
|
|
9
|
+
const exists = await pg.query('select space_id from site.spaces where space_id=$1', [id]).then(el => el.rows?.[0]?.space_id);
|
|
10
|
+
if (!exists) { return reply.status(404).send('space not found: ' + id); }
|
|
11
|
+
|
|
12
|
+
const { referer } = headers;
|
|
13
|
+
|
|
14
|
+
const res = await dataUpdate({
|
|
15
|
+
pg,
|
|
16
|
+
table: 'site.spaces',
|
|
17
|
+
data: body,
|
|
18
|
+
id,
|
|
19
|
+
uid: user?.uid,
|
|
20
|
+
referer,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
return { id, ...res || {} };
|
|
24
24
|
}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
// space
|
|
2
|
-
import getSpaces from './controllers/getSpaces.js';
|
|
3
|
-
import insertSpace from './controllers/insertSpace.js';
|
|
4
|
-
import updateSpace from './controllers/updateSpace.js';
|
|
5
|
-
import deleteSpace from './controllers/deleteSpace.js';
|
|
6
|
-
|
|
7
|
-
const params = {
|
|
8
|
-
config: {
|
|
9
|
-
policy: [
|
|
10
|
-
'public'
|
|
11
|
-
]
|
|
12
|
-
}
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export default async function route(app) {
|
|
16
|
-
app.get('/cms-space/:id?', params, getSpaces);
|
|
17
|
-
app.post('/cms-space/:id?', params, insertSpace);
|
|
18
|
-
app.put('/cms-space/:id?', params, updateSpace);
|
|
19
|
-
app.delete('/cms-space/:id', params, deleteSpace);
|
|
20
|
-
}
|
|
1
|
+
// space
|
|
2
|
+
import getSpaces from './controllers/getSpaces.js';
|
|
3
|
+
import insertSpace from './controllers/insertSpace.js';
|
|
4
|
+
import updateSpace from './controllers/updateSpace.js';
|
|
5
|
+
import deleteSpace from './controllers/deleteSpace.js';
|
|
6
|
+
|
|
7
|
+
const params = {
|
|
8
|
+
config: {
|
|
9
|
+
policy: [
|
|
10
|
+
'public'
|
|
11
|
+
]
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export default async function route(app) {
|
|
16
|
+
app.get('/cms-space/:id?', params, getSpaces);
|
|
17
|
+
app.post('/cms-space/:id?', params, insertSpace);
|
|
18
|
+
app.put('/cms-space/:id?', params, updateSpace);
|
|
19
|
+
app.delete('/cms-space/:id', params, deleteSpace);
|
|
20
|
+
}
|
|
@@ -1,160 +1,160 @@
|
|
|
1
|
-
import { config, logger, dataInsert, pgClients } from '@opengis/fastify-table/utils.js';
|
|
2
|
-
|
|
3
|
-
import updateCustomContentTable from '../utils/updateCustomContentTable.js'; // custom table
|
|
4
|
-
import updateContents from '../utils/updateContents.js'; // site.contents + site.content_data
|
|
5
|
-
|
|
6
|
-
const columns = [
|
|
7
|
-
{
|
|
8
|
-
name: 'slug',
|
|
9
|
-
label: 'Slug',
|
|
10
|
-
type: 'slug',
|
|
11
|
-
parent: 'title',
|
|
12
|
-
required: true
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
name: 'title',
|
|
16
|
-
label: 'Заголовок',
|
|
17
|
-
type: 'text',
|
|
18
|
-
required: true
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
name: 'status',
|
|
22
|
-
label: 'Статус',
|
|
23
|
-
type: 'select',
|
|
24
|
-
data: "content.status",
|
|
25
|
-
required: true
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
name: 'published_at',
|
|
29
|
-
label: 'Дата публікації',
|
|
30
|
-
type: 'date',
|
|
31
|
-
required: true
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
name: 'is_pin',
|
|
35
|
-
label: 'Закріпити контент',
|
|
36
|
-
type: 'boolean',
|
|
37
|
-
required: false,
|
|
38
|
-
default: 'false',
|
|
39
|
-
hidden: true,
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
name: 'meta',
|
|
43
|
-
label: 'Meta',
|
|
44
|
-
type: 'datalist',
|
|
45
|
-
hidden: true,
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
name: 'created_at',
|
|
49
|
-
label: 'Дата та час створення',
|
|
50
|
-
type: 'datetime',
|
|
51
|
-
default: 'now()',
|
|
52
|
-
hidden: true,
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
name: 'updated_at',
|
|
56
|
-
label: 'Дата та час редагування',
|
|
57
|
-
type: 'datetime',
|
|
58
|
-
default: 'now()',
|
|
59
|
-
hidden: true,
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
name: 'created_by',
|
|
63
|
-
type: 'text',
|
|
64
|
-
label: 'Автор',
|
|
65
|
-
hidden: true
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
name: 'updated_by',
|
|
69
|
-
type: 'text',
|
|
70
|
-
label: 'Редактор',
|
|
71
|
-
default: 'now()',
|
|
72
|
-
hidden: true
|
|
73
|
-
}
|
|
74
|
-
];
|
|
75
|
-
|
|
76
|
-
export default async function builderPost(req, reply) {
|
|
77
|
-
const { pg = pgClients.client, user = {}, body = {} } = req;
|
|
78
|
-
|
|
79
|
-
if (!pg?.pk?.['site.content_types']) {
|
|
80
|
-
return reply.status(404).send('table not found');
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (!body.name) {
|
|
84
|
-
return reply.status(400).send('not enough body params: name');
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (typeof body.name !== 'string') {
|
|
88
|
-
return reply.status(400).send('invalid body params: name not as string');
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const rowCount = await pg.query('select content_type_id as id from site.content_types where name=$1', [body.name]).then(el => el.rowCount);
|
|
92
|
-
|
|
93
|
-
if (rowCount > 0) {
|
|
94
|
-
return reply.status(400).send('Тип контенту з даною назвою вже існує');
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const tablename = body.type === 'collection' && true ? body.name.toLowerCase().replace(/ /g, '').replace(/'/g, "''").replace(/'/g, '').replace(/-/g, '_') : undefined; // customTable
|
|
98
|
-
|
|
99
|
-
const client = await pg.connect();
|
|
100
|
-
|
|
101
|
-
try {
|
|
102
|
-
await client.query('BEGIN');
|
|
103
|
-
|
|
104
|
-
const columns1 = (body.fields || body.columns || columns.filter(el => !el.hidden)).filter(el => el.name).map(el => Object.assign(el, { name: el.name.toLowerCase() })); // for rest crud
|
|
105
|
-
|
|
106
|
-
if (body.type === 'single') {
|
|
107
|
-
const singleColumns = [
|
|
108
|
-
{
|
|
109
|
-
name: 'main_image',
|
|
110
|
-
label: 'Головне зображення',
|
|
111
|
-
type: 'image',
|
|
112
|
-
required: false
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
name: 'single_body',
|
|
116
|
-
label: 'Контент',
|
|
117
|
-
type: 'richtext',
|
|
118
|
-
required: false
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
name: 'single_sections',
|
|
122
|
-
label: 'Секції',
|
|
123
|
-
type: 'reference',
|
|
124
|
-
required: false
|
|
125
|
-
},
|
|
126
|
-
]
|
|
127
|
-
columns1.push(...singleColumns);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
const { rows = [] } = await dataInsert({
|
|
131
|
-
pg: client,
|
|
132
|
-
table: 'site.content_types',
|
|
133
|
-
data: {
|
|
134
|
-
...body,
|
|
135
|
-
table_name: tablename,
|
|
136
|
-
columns: columns1,
|
|
137
|
-
},
|
|
138
|
-
uid: user?.uid,
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
Object.assign(body, { slug: body.slug || body.name });
|
|
142
|
-
|
|
143
|
-
if (tablename) {
|
|
144
|
-
await updateCustomContentTable({ pg: client, id: rows?.[0]?.content_type_id, columns });
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const res = await updateContents(client, rows?.[0]?.content_type_id, body, user?.uid);
|
|
148
|
-
Object.assign(rows?.[0], res || {}); // update rows with contents
|
|
149
|
-
|
|
150
|
-
await client.query('COMMIT');
|
|
151
|
-
|
|
152
|
-
return reply.status(200).send({ id: rows?.[0]?.content_type_id, rows });
|
|
153
|
-
} catch (err) {
|
|
154
|
-
await client.query('ROLLBACK');
|
|
155
|
-
logger.file('cms/contentType', { error: err.toString(), stack: err.stack });
|
|
156
|
-
return reply.status(500).send('Помилка при додаванні типу контенту');
|
|
157
|
-
} finally {
|
|
158
|
-
client.release();
|
|
159
|
-
}
|
|
160
|
-
}
|
|
1
|
+
import { config, logger, dataInsert, pgClients } from '@opengis/fastify-table/utils.js';
|
|
2
|
+
|
|
3
|
+
import updateCustomContentTable from '../utils/updateCustomContentTable.js'; // custom table
|
|
4
|
+
import updateContents from '../utils/updateContents.js'; // site.contents + site.content_data
|
|
5
|
+
|
|
6
|
+
const columns = [
|
|
7
|
+
{
|
|
8
|
+
name: 'slug',
|
|
9
|
+
label: 'Slug',
|
|
10
|
+
type: 'slug',
|
|
11
|
+
parent: 'title',
|
|
12
|
+
required: true
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
name: 'title',
|
|
16
|
+
label: 'Заголовок',
|
|
17
|
+
type: 'text',
|
|
18
|
+
required: true
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: 'status',
|
|
22
|
+
label: 'Статус',
|
|
23
|
+
type: 'select',
|
|
24
|
+
data: "content.status",
|
|
25
|
+
required: true
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: 'published_at',
|
|
29
|
+
label: 'Дата публікації',
|
|
30
|
+
type: 'date',
|
|
31
|
+
required: true
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: 'is_pin',
|
|
35
|
+
label: 'Закріпити контент',
|
|
36
|
+
type: 'boolean',
|
|
37
|
+
required: false,
|
|
38
|
+
default: 'false',
|
|
39
|
+
hidden: true,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: 'meta',
|
|
43
|
+
label: 'Meta',
|
|
44
|
+
type: 'datalist',
|
|
45
|
+
hidden: true,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: 'created_at',
|
|
49
|
+
label: 'Дата та час створення',
|
|
50
|
+
type: 'datetime',
|
|
51
|
+
default: 'now()',
|
|
52
|
+
hidden: true,
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: 'updated_at',
|
|
56
|
+
label: 'Дата та час редагування',
|
|
57
|
+
type: 'datetime',
|
|
58
|
+
default: 'now()',
|
|
59
|
+
hidden: true,
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: 'created_by',
|
|
63
|
+
type: 'text',
|
|
64
|
+
label: 'Автор',
|
|
65
|
+
hidden: true
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: 'updated_by',
|
|
69
|
+
type: 'text',
|
|
70
|
+
label: 'Редактор',
|
|
71
|
+
default: 'now()',
|
|
72
|
+
hidden: true
|
|
73
|
+
}
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
export default async function builderPost(req, reply) {
|
|
77
|
+
const { pg = pgClients.client, user = {}, body = {} } = req;
|
|
78
|
+
|
|
79
|
+
if (!pg?.pk?.['site.content_types']) {
|
|
80
|
+
return reply.status(404).send('table not found');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (!body.name) {
|
|
84
|
+
return reply.status(400).send('not enough body params: name');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (typeof body.name !== 'string') {
|
|
88
|
+
return reply.status(400).send('invalid body params: name not as string');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const rowCount = await pg.query('select content_type_id as id from site.content_types where name=$1', [body.name]).then(el => el.rowCount);
|
|
92
|
+
|
|
93
|
+
if (rowCount > 0) {
|
|
94
|
+
return reply.status(400).send('Тип контенту з даною назвою вже існує');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const tablename = body.type === 'collection' && true ? body.name.toLowerCase().replace(/ /g, '').replace(/'/g, "''").replace(/'/g, '').replace(/-/g, '_') : undefined; // customTable
|
|
98
|
+
|
|
99
|
+
const client = await pg.connect();
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
await client.query('BEGIN');
|
|
103
|
+
|
|
104
|
+
const columns1 = (body.fields || body.columns || columns.filter(el => !el.hidden)).filter(el => el.name).map(el => Object.assign(el, { name: el.name.toLowerCase() })); // for rest crud
|
|
105
|
+
|
|
106
|
+
if (body.type === 'single') {
|
|
107
|
+
const singleColumns = [
|
|
108
|
+
{
|
|
109
|
+
name: 'main_image',
|
|
110
|
+
label: 'Головне зображення',
|
|
111
|
+
type: 'image',
|
|
112
|
+
required: false
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
name: 'single_body',
|
|
116
|
+
label: 'Контент',
|
|
117
|
+
type: 'richtext',
|
|
118
|
+
required: false
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
name: 'single_sections',
|
|
122
|
+
label: 'Секції',
|
|
123
|
+
type: 'reference',
|
|
124
|
+
required: false
|
|
125
|
+
},
|
|
126
|
+
]
|
|
127
|
+
columns1.push(...singleColumns);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const { rows = [] } = await dataInsert({
|
|
131
|
+
pg: client,
|
|
132
|
+
table: 'site.content_types',
|
|
133
|
+
data: {
|
|
134
|
+
...body,
|
|
135
|
+
table_name: tablename,
|
|
136
|
+
columns: columns1,
|
|
137
|
+
},
|
|
138
|
+
uid: user?.uid,
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
Object.assign(body, { slug: body.slug || body.name });
|
|
142
|
+
|
|
143
|
+
if (tablename) {
|
|
144
|
+
await updateCustomContentTable({ pg: client, id: rows?.[0]?.content_type_id, columns });
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const res = await updateContents(client, rows?.[0]?.content_type_id, body, user?.uid);
|
|
148
|
+
Object.assign(rows?.[0], res || {}); // update rows with contents
|
|
149
|
+
|
|
150
|
+
await client.query('COMMIT');
|
|
151
|
+
|
|
152
|
+
return reply.status(200).send({ id: rows?.[0]?.content_type_id, rows });
|
|
153
|
+
} catch (err) {
|
|
154
|
+
await client.query('ROLLBACK');
|
|
155
|
+
logger.file('cms/contentType', { error: err.toString(), stack: err.stack });
|
|
156
|
+
return reply.status(500).send('Помилка при додаванні типу контенту');
|
|
157
|
+
} finally {
|
|
158
|
+
client.release();
|
|
159
|
+
}
|
|
160
|
+
}
|
|
@@ -1,54 +1,54 @@
|
|
|
1
|
-
import { logger, pgClients } from '@opengis/fastify-table/utils.js';
|
|
2
|
-
|
|
3
|
-
const maxLimit = 100;
|
|
4
|
-
|
|
5
|
-
export default async function builderList({ pg = pgClients.client, query = {} }, reply) {
|
|
6
|
-
if (!pg) {
|
|
7
|
-
return reply.status(200).send({ total: 0, msg: 'empty pg', rows: [] });
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const limit = Math.min(maxLimit, query.limit || 16);
|
|
11
|
-
const offset = query.page && query.page > 0 ? (query.page - 1) * limit : 0;
|
|
12
|
-
|
|
13
|
-
const q = `select a.content_type_id as id, a.name, a.title, a.description, a.table_name as table, type, columns, a.include_search, json_build_object('locales', locales, 'default_locale', default_locale, 'name', space_name) as space FROM site.content_types a
|
|
14
|
-
left join lateral ( select locales, default_locale, name as space_name from site.spaces where space_id= 'default' limit 1) b on 1=1
|
|
15
|
-
where ${query.type === 'collection' ? `type='collection'` : (query.type === 'single' ? `type='single'` : '1=1')}`;
|
|
16
|
-
|
|
17
|
-
const where = query.search?.replace ? `(name ilike '%${query.search.replace(/'/, "''")}%' or title ilike '%${query.search.replace(/'/, "''")}%')` : '1=1';
|
|
18
|
-
const q1 = q + ` and ${where} order by case when status='archived' then true else false end limit ${limit} offset ${offset}`;
|
|
19
|
-
|
|
20
|
-
if (query.sql) return q1;
|
|
21
|
-
|
|
22
|
-
const { rows = [] } = await pg.query(q1);
|
|
23
|
-
|
|
24
|
-
const { total = 0, filtered = 0 } = await pg.query(`select
|
|
25
|
-
count(*)::int as total,
|
|
26
|
-
count(*) filter (where ${where})::int as filtered
|
|
27
|
-
from (${q})q`
|
|
28
|
-
).then(el => el.rows?.[0] || {});
|
|
29
|
-
|
|
30
|
-
await Promise.all(rows.map(async row => {
|
|
31
|
-
if (row.table && false) {
|
|
32
|
-
await pg.query('alter table data.' + row.table + ' add column if not exists created_at timestamp with time zone not null default now()');
|
|
33
|
-
await pg.query('alter table data.' + row.table + ' add column if not exists updated_at timestamp with time zone not null default now()');
|
|
34
|
-
await pg.query('alter table data.' + row.table + ' add column if not exists created_by text');
|
|
35
|
-
await pg.query('alter table data.' + row.table + ' add column if not exists updated_by text');
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const q2 = row.table
|
|
39
|
-
? `select count(*) from data."${row.table}" where $1=$1`
|
|
40
|
-
: `select count(*) from site.contents where $1=$1 and ${row.id === 'pages' ? `slug <> 'pages' and content_type_id in (select content_type_id from site.content_types where type = 'single' or content_type_id='pages')` : 'content_type_id=$1'}`;
|
|
41
|
-
|
|
42
|
-
const q3 = row.table
|
|
43
|
-
? `select updated_at from data."${row.table}" where $1=$1 order by updated_at desc limit 1`
|
|
44
|
-
: `select updated_at from site.content_data where content_id in ( select content_id from site.contents where content_type_id=$1 limit 1) order by updated_at desc limit 1`;
|
|
45
|
-
|
|
46
|
-
const count = await pg.queryCache(q2, { table: row.table ? `data.${row.table}` : 'site.content_data', args: [row.id] }).then(el => el.rows?.[0]?.count || '0');
|
|
47
|
-
|
|
48
|
-
const lastEdit = await pg.queryCache(q3, { table: row.table ? `data.${row.table}` : 'site.content_data', args: [row.id] }).then(el => el.rows?.[0]?.updated_at);
|
|
49
|
-
|
|
50
|
-
Object.assign(row, { columns: undefined, fields: row.columns?.length || '0', entries: +count, last_edit: lastEdit });
|
|
51
|
-
}));
|
|
52
|
-
|
|
53
|
-
return reply.status(200).send({ total, filtered, count: rows.length, provider: 'pg', rows });
|
|
54
|
-
}
|
|
1
|
+
import { logger, pgClients } from '@opengis/fastify-table/utils.js';
|
|
2
|
+
|
|
3
|
+
const maxLimit = 100;
|
|
4
|
+
|
|
5
|
+
export default async function builderList({ pg = pgClients.client, query = {} }, reply) {
|
|
6
|
+
if (!pg) {
|
|
7
|
+
return reply.status(200).send({ total: 0, msg: 'empty pg', rows: [] });
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const limit = Math.min(maxLimit, query.limit || 16);
|
|
11
|
+
const offset = query.page && query.page > 0 ? (query.page - 1) * limit : 0;
|
|
12
|
+
|
|
13
|
+
const q = `select a.content_type_id as id, a.name, a.title, a.description, a.table_name as table, type, columns, a.include_search, json_build_object('locales', locales, 'default_locale', default_locale, 'name', space_name) as space FROM site.content_types a
|
|
14
|
+
left join lateral ( select locales, default_locale, name as space_name from site.spaces where space_id= 'default' limit 1) b on 1=1
|
|
15
|
+
where ${query.type === 'collection' ? `type='collection'` : (query.type === 'single' ? `type='single'` : '1=1')}`;
|
|
16
|
+
|
|
17
|
+
const where = query.search?.replace ? `(name ilike '%${query.search.replace(/'/, "''")}%' or title ilike '%${query.search.replace(/'/, "''")}%')` : '1=1';
|
|
18
|
+
const q1 = q + ` and ${where} order by case when status='archived' then true else false end limit ${limit} offset ${offset}`;
|
|
19
|
+
|
|
20
|
+
if (query.sql) return q1;
|
|
21
|
+
|
|
22
|
+
const { rows = [] } = await pg.query(q1);
|
|
23
|
+
|
|
24
|
+
const { total = 0, filtered = 0 } = await pg.query(`select
|
|
25
|
+
count(*)::int as total,
|
|
26
|
+
count(*) filter (where ${where})::int as filtered
|
|
27
|
+
from (${q})q`
|
|
28
|
+
).then(el => el.rows?.[0] || {});
|
|
29
|
+
|
|
30
|
+
await Promise.all(rows.map(async row => {
|
|
31
|
+
if (row.table && false) {
|
|
32
|
+
await pg.query('alter table data.' + row.table + ' add column if not exists created_at timestamp with time zone not null default now()');
|
|
33
|
+
await pg.query('alter table data.' + row.table + ' add column if not exists updated_at timestamp with time zone not null default now()');
|
|
34
|
+
await pg.query('alter table data.' + row.table + ' add column if not exists created_by text');
|
|
35
|
+
await pg.query('alter table data.' + row.table + ' add column if not exists updated_by text');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const q2 = row.table
|
|
39
|
+
? `select count(*) from data."${row.table}" where $1=$1`
|
|
40
|
+
: `select count(*) from site.contents where $1=$1 and ${row.id === 'pages' ? `slug <> 'pages' and content_type_id in (select content_type_id from site.content_types where type = 'single' or content_type_id='pages')` : 'content_type_id=$1'}`;
|
|
41
|
+
|
|
42
|
+
const q3 = row.table
|
|
43
|
+
? `select updated_at from data."${row.table}" where $1=$1 order by updated_at desc limit 1`
|
|
44
|
+
: `select updated_at from site.content_data where content_id in ( select content_id from site.contents where content_type_id=$1 limit 1) order by updated_at desc limit 1`;
|
|
45
|
+
|
|
46
|
+
const count = await pg.queryCache(q2, { table: row.table ? `data.${row.table}` : 'site.content_data', args: [row.id] }).then(el => el.rows?.[0]?.count || '0');
|
|
47
|
+
|
|
48
|
+
const lastEdit = await pg.queryCache(q3, { table: row.table ? `data.${row.table}` : 'site.content_data', args: [row.id] }).then(el => el.rows?.[0]?.updated_at);
|
|
49
|
+
|
|
50
|
+
Object.assign(row, { columns: undefined, fields: row.columns?.length || '0', entries: +count, last_edit: lastEdit });
|
|
51
|
+
}));
|
|
52
|
+
|
|
53
|
+
return reply.status(200).send({ total, filtered, count: rows.length, provider: 'pg', rows });
|
|
54
|
+
}
|