@opengis/cms 0.0.59 → 0.0.61
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 +4 -4
- package/dist/{ArticlesPage-BjYzvTWM.js → ArticlesPage-CFjE_cw_.js} +3 -3
- package/dist/{CollectionsBreadcrumb-HePNJb-d.js → CollectionsBreadcrumb-BCxeRikP.js} +1 -1
- package/dist/CollectionsBreadcrumb.vue_vue_type_script_setup_true_lang-umRzB5mY.js +53 -0
- package/dist/{Dashboard-CXkg_pk8.js → Dashboard-C1eGscNd.js} +132 -132
- package/dist/EditCollectionPage-3Q57ptN3.js +188 -0
- package/dist/{MenuAddPage-QTnwCoGh.js → MenuAddPage-D-p3gFgm.js} +1 -1
- package/dist/{MenuBody-Bi0ONVZf.js → MenuBody-rN5j4YBu.js} +2 -2
- package/dist/{MenuItemPage-B7Y9KFyb.js → MenuItemPage-BoJw885D.js} +3 -3
- package/dist/{MenuList-BLIpeqSd.js → MenuList-DFEBS0NB.js} +53 -53
- package/dist/{MenuPage-3W6jZ15H.js → MenuPage-BCZB_S8j.js} +1 -1
- package/dist/{MenuWrapper-OrOv6sOb.js → MenuWrapper-AZ_8s-zd.js} +1 -1
- package/dist/{MonacoEditor-ByPT8pnv.js → MonacoEditor-Db-3Jc3E.js} +1 -1
- package/dist/MonacoEditor.vue_vue_type_script_setup_true_lang-B1DrxmQX.js +84 -0
- package/dist/{UniversalTable-GBd_pStq.js → UniversalTable-CzqPG-tY.js} +80 -80
- package/dist/{UniversalTablePagination-Dw2hc0nc.js → UniversalTablePagination-4gL47A7I.js} +46 -46
- package/dist/{contentForm-Buku-lel.js → contentForm-CLStrfSg.js} +49 -52
- package/dist/index.js +5 -5
- package/dist/{vs-builder-monaco-Cw-f19gc.js → vs-builder-monaco-B3Jj0V31.js} +1 -1
- package/package.json +69 -69
- package/server/migrations/fixes.sql +5 -2
- package/server/migrations/site.sql +4 -3
- package/server/routes/cms/controllers/deleteContent.js +7 -7
- package/server/routes/cms/controllers/getContent.js +6 -6
- package/server/routes/cms/controllers/getContentBySlug.js +13 -13
- package/server/routes/cms/controllers/getPermissions.js +15 -15
- package/server/routes/cms/controllers/insertContent.js +28 -19
- package/server/routes/cms/controllers/setPermissions.js +49 -49
- package/server/routes/cms/controllers/updateContent.js +12 -47
- package/server/routes/cms/utils/getCollection.js +1 -1
- package/server/routes/cms/utils/getSingle.js +1 -1
- package/server/routes/cms/utils/insertContentLocalization.js +1 -1
- package/server/routes/cms/utils/requestTranslation.js +73 -23
- package/server/routes/cms/utils/updateLocalization.js +1 -6
- package/server/routes/cmsSpace/controllers/deleteSpace.js +1 -0
- package/server/routes/cmsSpace/controllers/getSpaces.js +1 -0
- package/server/routes/cmsSpace/controllers/insertSpace.js +1 -0
- package/server/routes/cmsSpace/controllers/updateSpace.js +1 -0
- package/server/routes/contentType/controllers/contentTypeList.js +4 -11
- package/server/routes/contentType/controllers/editContentType.js +7 -25
- package/server/routes/contentType/controllers/getContentType.js +5 -13
- package/server/templates/select/core.user_mentioned.sql +1 -1
- package/dist/CollectionsBreadcrumb.vue_vue_type_script_setup_true_lang-BJh-tjam.js +0 -53
- package/dist/EditCollectionPage-CqYHpEON.js +0 -187
- package/dist/MonacoEditor.vue_vue_type_script_setup_true_lang-C8cip9Ci.js +0 -84
- package/dist/images/logo.png +0 -0
- package/dist/index.html +0 -29
- package/dist/vite.svg +0 -1
|
@@ -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
|
}
|
|
@@ -34,7 +34,7 @@ export default async function insertContent(req, reply) {
|
|
|
34
34
|
const { type, id = body?.id } = params;
|
|
35
35
|
|
|
36
36
|
if (!type) {
|
|
37
|
-
return reply.status(400).send('not enough params: type');
|
|
37
|
+
return reply.status(400).send({ error: 'not enough params: type', code: 400 });
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
const arr = config.pg ? await pg.query(`select array_agg(relname)::text[] from pg_class a
|
|
@@ -52,7 +52,7 @@ export default async function insertContent(req, reply) {
|
|
|
52
52
|
).then(el => el.rows?.[0]?.content_type_id) : null;
|
|
53
53
|
|
|
54
54
|
if (!arr.length && (ctypeId || type) !== 'pages') {
|
|
55
|
-
return reply.status(400).send('empty schema: data');
|
|
55
|
+
return reply.status(400).send({ error: 'empty schema: data', code: 400 });
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
const table = arr.find(el => el === params.type);
|
|
@@ -78,7 +78,7 @@ export default async function insertContent(req, reply) {
|
|
|
78
78
|
const ctid1 = body.content_type_id || ctid || 'pages';
|
|
79
79
|
|
|
80
80
|
if (!cid) {
|
|
81
|
-
return reply.status(404).send('contents not found');
|
|
81
|
+
return reply.status(404).send({ error: 'contents not found', code: 404 });
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
const columnList = columns?.map?.(el => el.name) || [];
|
|
@@ -106,19 +106,30 @@ export default async function insertContent(req, reply) {
|
|
|
106
106
|
);
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
+
const id1 = id || await pg.query('select next_id()').then(el => el.rows[0].next_id);
|
|
110
|
+
|
|
109
111
|
const client = await pg.connect();
|
|
110
112
|
|
|
111
113
|
try {
|
|
112
114
|
await client.query('begin');
|
|
115
|
+
await dataInsert({
|
|
116
|
+
pg: client,
|
|
117
|
+
table: 'site.content_types',
|
|
118
|
+
id: id1,
|
|
119
|
+
data: { ...body, type: 'single', name: body.slug },
|
|
120
|
+
uid: user?.uid,
|
|
121
|
+
});
|
|
113
122
|
const res = await dataInsert({
|
|
114
123
|
pg: client,
|
|
115
124
|
table: 'site.contents',
|
|
116
|
-
id,
|
|
117
|
-
data: { ...body, content_type_id:
|
|
125
|
+
id: id1,
|
|
126
|
+
data: { ...body, content_type_id: id1 },
|
|
118
127
|
uid: user?.uid,
|
|
119
|
-
})
|
|
128
|
+
});
|
|
120
129
|
|
|
121
|
-
if (!res?.content_id)
|
|
130
|
+
if (!res?.content_id) {
|
|
131
|
+
throw new Error('insert contents error');
|
|
132
|
+
}
|
|
122
133
|
|
|
123
134
|
await Promise.all(keys.map(async key => dataInsert({
|
|
124
135
|
pg: client,
|
|
@@ -155,7 +166,7 @@ export default async function insertContent(req, reply) {
|
|
|
155
166
|
};
|
|
156
167
|
} catch (err) {
|
|
157
168
|
await client.query('rollback');
|
|
158
|
-
return reply.status(500).send(err.toString());
|
|
169
|
+
return reply.status(500).send({ error: err.toString(), code: 500 });
|
|
159
170
|
} finally {
|
|
160
171
|
client.release();
|
|
161
172
|
}
|
|
@@ -163,7 +174,7 @@ export default async function insertContent(req, reply) {
|
|
|
163
174
|
|
|
164
175
|
// custom table
|
|
165
176
|
if (!table && !dbtable) {
|
|
166
|
-
return reply.status(400).send('invalid params: type');
|
|
177
|
+
return reply.status(400).send({ error: 'invalid params: type', code: 400 });
|
|
167
178
|
}
|
|
168
179
|
|
|
169
180
|
const client = await pg.connect();
|
|
@@ -172,7 +183,7 @@ export default async function insertContent(req, reply) {
|
|
|
172
183
|
await client.query('begin');
|
|
173
184
|
|
|
174
185
|
// const types = columns?.reduce?.((acc, curr) => ({ ...acc, [curr.name]: inputTypes[curr.type] || 'text' }), {}) || {};
|
|
175
|
-
const
|
|
186
|
+
const row = await dataInsert({
|
|
176
187
|
pg: client,
|
|
177
188
|
id,
|
|
178
189
|
table: 'data.' + `"${(table || dbtable)}"`,
|
|
@@ -181,18 +192,16 @@ export default async function insertContent(req, reply) {
|
|
|
181
192
|
uid: user?.uid,
|
|
182
193
|
}).catch(err => {
|
|
183
194
|
if (err.message?.includes?.('unique constraint')) {
|
|
184
|
-
throw new Error('Порушенні унікальності: ' + err.message?.match?.(/([^']+)/g)?.[1]);
|
|
195
|
+
throw new Error('Порушенні унікальності: ' + err.message?.match?.(/([^']+)/g)?.[1] || err.message.split('unique constraint')[1]);
|
|
185
196
|
}
|
|
186
197
|
throw err;
|
|
187
|
-
})
|
|
188
|
-
|
|
189
|
-
const idRes = rows?.[0]?.id;
|
|
198
|
+
});
|
|
190
199
|
|
|
191
|
-
if (!
|
|
200
|
+
if (!row?.id) {
|
|
192
201
|
throw new Error('content insert error');
|
|
193
202
|
}
|
|
194
203
|
|
|
195
|
-
await updateLocalization(client,
|
|
204
|
+
await updateLocalization(client, row.id, body, ctid, user?.uid);
|
|
196
205
|
|
|
197
206
|
if (body?.tag_list?.length) {
|
|
198
207
|
await Promise.all(body.tag_list.map(async tag => dataInsert({
|
|
@@ -200,7 +209,7 @@ export default async function insertContent(req, reply) {
|
|
|
200
209
|
table: 'site.tag_data',
|
|
201
210
|
data: {
|
|
202
211
|
tag_id: tag,
|
|
203
|
-
data_id: id ||
|
|
212
|
+
data_id: id || row.id,
|
|
204
213
|
},
|
|
205
214
|
uid: user?.uid,
|
|
206
215
|
})));
|
|
@@ -208,10 +217,10 @@ export default async function insertContent(req, reply) {
|
|
|
208
217
|
|
|
209
218
|
await client.query('commit');
|
|
210
219
|
|
|
211
|
-
return reply.status(200).send({ id:
|
|
220
|
+
return reply.status(200).send({ id: row.id, rows: [row] });
|
|
212
221
|
} catch (err) {
|
|
213
222
|
await client.query('rollback');
|
|
214
|
-
return reply.status(500).send(err.toString());
|
|
223
|
+
return reply.status(500).send({ error: err.toString(), code: 500 });
|
|
215
224
|
} finally {
|
|
216
225
|
client.release();
|
|
217
226
|
}
|
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
import { logger, pgClients, dataInsert } from '@opengis/fastify-table/utils.js';
|
|
2
|
-
|
|
3
|
-
export default async function setPermissions(req, reply) {
|
|
4
|
-
const { pg = pgClients.client, params = {}, user = {}, body = {} } = req;
|
|
5
|
-
|
|
6
|
-
if (!user?.uid) {
|
|
7
|
-
return reply.status(401).send('unauthorized');
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
if (!params.id) {
|
|
11
|
-
return reply.status(400).send('not enough params: id');
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const client = await pg.connect()
|
|
15
|
-
const result = {};
|
|
16
|
-
try {
|
|
17
|
-
await client.query('BEGIN');
|
|
18
|
-
|
|
19
|
-
const { rowCount = 0 } = await client.query(
|
|
20
|
-
`delete from site.permissions where user_id=$1`,
|
|
21
|
-
[params.id].filter(Boolean),
|
|
22
|
-
);
|
|
23
|
-
|
|
24
|
-
Object.assign(result, { deleted: rowCount });
|
|
25
|
-
|
|
26
|
-
if (Array.isArray(body.permissions) && body.permissions?.length) {
|
|
27
|
-
body.permissions.forEach((el) => {
|
|
28
|
-
Object.assign(el, { user_id: el.user_id || params.id });
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
await Promise.all(body.permissions.map(async (el) => dataInsert({
|
|
32
|
-
pg: client,
|
|
33
|
-
table: 'site.permissions',
|
|
34
|
-
data: el,
|
|
35
|
-
uid: user.uid,
|
|
36
|
-
})));
|
|
37
|
-
|
|
38
|
-
Object.assign(result, { inserted: body.permissions.length });
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
await client.query('COMMIT');
|
|
42
|
-
return reply.status(200).send(result);
|
|
43
|
-
} catch (err) {
|
|
44
|
-
await client.query('ROLLBACK');
|
|
45
|
-
logger.file('cms/permissions', { error: err.toString(), stack: err.stack });
|
|
46
|
-
return reply.status(500).send('set permissions error');
|
|
47
|
-
} finally {
|
|
48
|
-
client.release();
|
|
49
|
-
}
|
|
1
|
+
import { logger, pgClients, dataInsert } from '@opengis/fastify-table/utils.js';
|
|
2
|
+
|
|
3
|
+
export default async function setPermissions(req, reply) {
|
|
4
|
+
const { pg = pgClients.client, params = {}, user = {}, body = {} } = req;
|
|
5
|
+
|
|
6
|
+
if (!user?.uid) {
|
|
7
|
+
return reply.status(401).send('unauthorized');
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (!params.id) {
|
|
11
|
+
return reply.status(400).send('not enough params: id');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const client = await pg.connect()
|
|
15
|
+
const result = {};
|
|
16
|
+
try {
|
|
17
|
+
await client.query('BEGIN');
|
|
18
|
+
|
|
19
|
+
const { rowCount = 0 } = await client.query(
|
|
20
|
+
`delete from site.permissions where user_id=$1`,
|
|
21
|
+
[params.id].filter(Boolean),
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
Object.assign(result, { deleted: rowCount });
|
|
25
|
+
|
|
26
|
+
if (Array.isArray(body.permissions) && body.permissions?.length) {
|
|
27
|
+
body.permissions.forEach((el) => {
|
|
28
|
+
Object.assign(el, { user_id: el.user_id || params.id });
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
await Promise.all(body.permissions.map(async (el) => dataInsert({
|
|
32
|
+
pg: client,
|
|
33
|
+
table: 'site.permissions',
|
|
34
|
+
data: el,
|
|
35
|
+
uid: user.uid,
|
|
36
|
+
})));
|
|
37
|
+
|
|
38
|
+
Object.assign(result, { inserted: body.permissions.length });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
await client.query('COMMIT');
|
|
42
|
+
return reply.status(200).send(result);
|
|
43
|
+
} catch (err) {
|
|
44
|
+
await client.query('ROLLBACK');
|
|
45
|
+
logger.file('cms/permissions', { error: err.toString(), stack: err.stack });
|
|
46
|
+
return reply.status(500).send('set permissions error');
|
|
47
|
+
} finally {
|
|
48
|
+
client.release();
|
|
49
|
+
}
|
|
50
50
|
}
|
|
@@ -34,26 +34,26 @@ export default async function updateContent(req, reply) {
|
|
|
34
34
|
const { type, id } = params;
|
|
35
35
|
|
|
36
36
|
if (!type) {
|
|
37
|
-
return reply.status(400).send('not enough params: type');
|
|
37
|
+
return reply.status(400).send({ error: 'not enough params: type', code: 400 });
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
if (!id) {
|
|
41
|
-
return reply.status(400).send('not enough params: id');
|
|
41
|
+
return reply.status(400).send({ error: 'not enough params: id', code: 400 });
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
if (!Object.keys(body || {}).length) {
|
|
45
|
-
return reply.status(400).send('empty body');
|
|
45
|
+
return reply.status(400).send({ error: 'empty body', code: 400 });
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
// order priority - custom columns -> default for pages
|
|
49
49
|
const { ctid, ctname, dbtable, columns: contentColumns = [] } = await pg.query('select content_type_id as ctid, name as ctname, table_name as dbtable, columns from site.content_types where content_type_id in (select content_type_id from site.contents where content_id=$1) or content_type_id=$2 order by content_type_id = \'pages\'', [id, type]).then(el => el.rows?.[0] || {});
|
|
50
50
|
|
|
51
|
-
const arr =
|
|
51
|
+
const arr = pg ? await pg.query(`select array_agg(relname)::text[] from pg_class a
|
|
52
52
|
left join pg_namespace b on a.relnamespace=b.oid
|
|
53
53
|
where a.relam=2 and b.nspname='data'`).then(el => el.rows?.[0]?.array_agg || []) : [];
|
|
54
54
|
|
|
55
55
|
if (!arr.length && type !== 'pages') {
|
|
56
|
-
return reply.status(400).send('empty schema: data');
|
|
56
|
+
return reply.status(400).send({ error: 'empty schema: data', code: 400 });
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
const table = arr.find(el => el === params.type);
|
|
@@ -90,25 +90,16 @@ export default async function updateContent(req, reply) {
|
|
|
90
90
|
const ctid1 = body.content_type_id || ctid;
|
|
91
91
|
|
|
92
92
|
if (!cid) {
|
|
93
|
-
return reply.status(404).send('contents not found');
|
|
93
|
+
return reply.status(404).send({ error: 'contents not found', code: 404 });
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
// ? deprecated, blocks if only default columns provided, therefore commented for now
|
|
97
|
-
// const contentId = cid === 'pages'
|
|
98
|
-
// ? await pg.query('select content_id from site.content_data where object_id=$1', [id]).then(el => el.rows?.[0]?.content_id)
|
|
99
|
-
// : cid;
|
|
100
|
-
|
|
101
|
-
// if (!contentId) {
|
|
102
|
-
// return reply.status(404).send('contents not found: 2');
|
|
103
|
-
// }
|
|
104
|
-
|
|
105
96
|
const columnList = columns?.map?.(el => el.name) || [];
|
|
106
97
|
const types = columns?.reduce?.((acc, curr) => ({ ...acc, [curr.name]: curr.type || 'text' }), {}) || {};
|
|
107
98
|
const keys = Object.keys(body || {}).filter(key => columnList.includes(key) && !defaultColumns.includes(key));
|
|
108
99
|
|
|
109
100
|
|
|
110
101
|
if (!Object.keys(body || {}).length) {
|
|
111
|
-
return reply.status(400).send('invalid payload');
|
|
102
|
+
return reply.status(400).send({ error: 'invalid payload', code: 400 });
|
|
112
103
|
}
|
|
113
104
|
|
|
114
105
|
const blocks = await pg.query(`select json_object_agg(field_key,field_value) from site.content_data where content_id=$1 and field_type='reference'`, [id])
|
|
@@ -117,19 +108,9 @@ export default async function updateContent(req, reply) {
|
|
|
117
108
|
const emptyBlock = Object.keys(body).find(key => blocks[key] && (!body[key] || typeof body[key] !== 'object' || Object.keys(body[key] || {}) === 0));
|
|
118
109
|
|
|
119
110
|
if (emptyBlock) {
|
|
120
|
-
return reply.status(400).send('access restricted: empty/invalid block ' + emptyBlock);
|
|
111
|
+
return reply.status(400).send({ error: 'access restricted: empty/invalid block ' + emptyBlock, code: 400 });
|
|
121
112
|
}
|
|
122
113
|
|
|
123
|
-
const single = await pg.query(
|
|
124
|
-
`select content_id, content_type_id, slug FROM site.contents
|
|
125
|
-
where content_id=$1`, [params.id]
|
|
126
|
-
).then(el => el.rows?.[0]);
|
|
127
|
-
|
|
128
|
-
const customCtExists = await pg.query(
|
|
129
|
-
`select 1 FROM site.content_types
|
|
130
|
-
where content_type_id=$1`, [params.id]
|
|
131
|
-
).then(el => el.rowCount || 0);
|
|
132
|
-
|
|
133
114
|
const client = await pg.connect();
|
|
134
115
|
|
|
135
116
|
try {
|
|
@@ -137,19 +118,6 @@ export default async function updateContent(req, reply) {
|
|
|
137
118
|
|
|
138
119
|
const res = {};
|
|
139
120
|
|
|
140
|
-
if (single && !customCtExists && (single?.content_type_id === 'pages' || single?.content_type_id === params.id)) {
|
|
141
|
-
// const loadTable = await getTemplate('table', 'single.default.table');
|
|
142
|
-
// const { columns: defaultColumns } = loadTable || {};
|
|
143
|
-
const res1 = await dataInsert({
|
|
144
|
-
pg: client,
|
|
145
|
-
table: 'site.content_types',
|
|
146
|
-
id: params.id,
|
|
147
|
-
data: { ...body, type: 'single', name: body.name === 'pages' ? (single.slug || params.id) : (body.name || body.slug) /*, columns: defaultColumns*/ },
|
|
148
|
-
uid: user?.uid,
|
|
149
|
-
});
|
|
150
|
-
Object.assign(res, res1);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
121
|
const res1 = await dataUpdate({
|
|
154
122
|
pg: client,
|
|
155
123
|
table: 'site.contents',
|
|
@@ -159,9 +127,6 @@ export default async function updateContent(req, reply) {
|
|
|
159
127
|
});
|
|
160
128
|
Object.assign(res, res1);
|
|
161
129
|
|
|
162
|
-
// if (contentId) {
|
|
163
|
-
// await client.query(`delete from site.content_data where content_id=$1`, [contentId]);
|
|
164
|
-
// }
|
|
165
130
|
const objectId = (ctname === 'pages' || ['single', 'pages'].includes(type)) && id ? id : cid;
|
|
166
131
|
await client.query(`delete from site.content_data where object_id=$1`, [objectId]);
|
|
167
132
|
await Promise.all(keys.map(async key => dataInsert({
|
|
@@ -204,14 +169,14 @@ export default async function updateContent(req, reply) {
|
|
|
204
169
|
};
|
|
205
170
|
} catch (err) {
|
|
206
171
|
await client.query('rollback');
|
|
207
|
-
return reply.status(500).send(err.toString());
|
|
172
|
+
return reply.status(500).send({ error: err.toString(), code: 500 });
|
|
208
173
|
} finally {
|
|
209
174
|
client.release();
|
|
210
175
|
}
|
|
211
176
|
}
|
|
212
177
|
|
|
213
178
|
if (!table && !dbtable) {
|
|
214
|
-
return reply.status(400).send('invalid params: type');
|
|
179
|
+
return reply.status(400).send({ error: 'invalid params: type', code: 400 });
|
|
215
180
|
}
|
|
216
181
|
|
|
217
182
|
const client = await pg.connect();
|
|
@@ -254,13 +219,13 @@ export default async function updateContent(req, reply) {
|
|
|
254
219
|
await client.query('commit');
|
|
255
220
|
|
|
256
221
|
if (!result?.id) {
|
|
257
|
-
return reply.status(404).send('content not found');
|
|
222
|
+
return reply.status(404).send({ error: 'content not found', code: 404 });
|
|
258
223
|
}
|
|
259
224
|
|
|
260
225
|
return reply.status(200).send(result);
|
|
261
226
|
} catch (err) {
|
|
262
227
|
await client.query('rollback');
|
|
263
|
-
return reply.status(500).send(err.toString());
|
|
228
|
+
return reply.status(500).send({ error: err.toString(), code: 500 });
|
|
264
229
|
} finally {
|
|
265
230
|
client.release();
|
|
266
231
|
}
|
|
@@ -70,7 +70,7 @@ export default async function getCollection({
|
|
|
70
70
|
|
|
71
71
|
const finalColumns = (defaultColumns || []).concat(columns1.filter(col => defaultColumns.findIndex(el => el.name === col.name) === -1));
|
|
72
72
|
|
|
73
|
-
finalColumns.filter(el => el.
|
|
73
|
+
finalColumns.filter(el => el.defaultColumn).forEach(col => {
|
|
74
74
|
const { name, localization } = columns1.find(item => item.name === col.name) || {};
|
|
75
75
|
if (name) {
|
|
76
76
|
Object.assign(col, { localization });
|
|
@@ -26,7 +26,7 @@ export default async function getSingle({
|
|
|
26
26
|
|
|
27
27
|
const columns = defaultColumns.concat(customColumns.filter(col => defaultColumns.findIndex(el => el.name === col.name) === -1));
|
|
28
28
|
|
|
29
|
-
columns.filter(el => el.
|
|
29
|
+
columns.filter(el => el.defaultColumn).forEach(col => {
|
|
30
30
|
const { name, localization } = customColumns.find(item => item.name === col.name) || {};
|
|
31
31
|
if (name) {
|
|
32
32
|
Object.assign(col, { localization });
|
|
@@ -41,7 +41,7 @@ export default async function insertContentLocalization({ send = () => { }, tabl
|
|
|
41
41
|
const obj = { ...row, ...localization };
|
|
42
42
|
|
|
43
43
|
const entries = Object.entries(obj).filter(([key, value]) => value && schemaKeys.includes(key) && (typeof value === 'string' || (Array.isArray(value) && value?.[0] && typeof value?.[0] === 'object' && Object.keys(value).length)));
|
|
44
|
-
// do not old localization
|
|
44
|
+
// do not overwrite old localization by default
|
|
45
45
|
const filteredEntries = skip && targetLocalization ? entries.filter(([key]) => !Object.keys(targetLocalization).includes(key)) : entries;
|
|
46
46
|
|
|
47
47
|
if (skip && targetLocalization && !filteredEntries.length) {
|
|
@@ -5,17 +5,26 @@ const { host = 'https://translate.softpro.ua', key = '' } = config.integrations?
|
|
|
5
5
|
const divider = ' <divider> ';
|
|
6
6
|
|
|
7
7
|
// Wrap dot notation keys in quotes
|
|
8
|
-
export const arrayToPhrases = (arr, prefix = 'item') => {
|
|
8
|
+
export const arrayToPhrases = (arr, prefix = 'item', mainIdx = null) => {
|
|
9
9
|
if (!arr || !arr.length) return [];
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
|
|
11
|
+
return arr.flatMap((obj, idx) => {
|
|
12
|
+
const currentMainIdx = mainIdx ?? idx;
|
|
13
|
+
|
|
14
|
+
return Object.entries(obj).flatMap(([key, value]) => {
|
|
15
|
+
if (Array.isArray(value)) {
|
|
16
|
+
return arrayToPhrases(value, `${prefix}.${key}`, currentMainIdx);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return [{
|
|
20
|
+
prefix,
|
|
21
|
+
value,
|
|
22
|
+
key,
|
|
23
|
+
mainIdx: currentMainIdx,
|
|
24
|
+
idx,
|
|
25
|
+
}];
|
|
26
|
+
});
|
|
27
|
+
});
|
|
19
28
|
};
|
|
20
29
|
|
|
21
30
|
export default async function requestTranslation(entries, from = 'uk', to) {
|
|
@@ -26,17 +35,29 @@ export default async function requestTranslation(entries, from = 'uk', to) {
|
|
|
26
35
|
|
|
27
36
|
// Translate each phrase independently
|
|
28
37
|
const translatedPhrases = await Promise.all(
|
|
29
|
-
phrasesWithMeta.map(async ({ key, idx, prefix, value }) => {
|
|
38
|
+
phrasesWithMeta.map(async ({ key, idx, prefix, value, mainIdx }) => {
|
|
30
39
|
if (!value || typeof value === 'number' || value?.startsWith?.('/files/')) {
|
|
31
|
-
return { key, idx, prefix, value, skip: true }; // fallback to original
|
|
40
|
+
return { key, idx, mainIdx, prefix, value, skip: true }; // fallback to original
|
|
32
41
|
}
|
|
33
42
|
|
|
34
43
|
try {
|
|
35
|
-
const parts =
|
|
36
|
-
|
|
37
|
-
|
|
44
|
+
const parts =
|
|
45
|
+
typeof value === 'string' && value.startsWith('<') && value.endsWith('>')
|
|
46
|
+
? [...value.matchAll(/(<[^>]+>)|([^<]+)/gs)].map(([, tag, str]) =>
|
|
47
|
+
tag
|
|
48
|
+
? { tag }
|
|
49
|
+
: { str, tIndex: null, skip: !str.trim() || /^[—–\-.: ]+$/.test(str.trim()) ? true : false, preSpace: str.startsWith(' ') ? ' ' : '', postSpace: str.endsWith(' ') ? ' ' : '' }
|
|
50
|
+
)
|
|
51
|
+
: [{ str: value, tIndex: 0, skip: false }];
|
|
38
52
|
|
|
39
|
-
|
|
53
|
+
// assign translation index only to fragments that should be translated
|
|
54
|
+
const q = [];
|
|
55
|
+
parts.forEach((p) => {
|
|
56
|
+
if (!p.tag && !p.skip) {
|
|
57
|
+
p.tIndex = q.length;
|
|
58
|
+
q.push(p.str);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
40
61
|
|
|
41
62
|
const resp = await fetch(`${host}/translate`, {
|
|
42
63
|
method: "POST",
|
|
@@ -57,20 +78,49 @@ export default async function requestTranslation(entries, from = 'uk', to) {
|
|
|
57
78
|
}
|
|
58
79
|
|
|
59
80
|
const body = await resp.json();
|
|
60
|
-
const
|
|
61
|
-
|
|
81
|
+
const translated = body.translatedText || [];
|
|
82
|
+
|
|
83
|
+
const resultValue = parts
|
|
84
|
+
.map((p) => {
|
|
85
|
+
if (p.tag) return p.tag;
|
|
86
|
+
if (p.skip) return p.str; // keep original punctuation/whitespace
|
|
87
|
+
const txt = translated[p.tIndex] ?? p.str ?? '';
|
|
88
|
+
return `${p.preSpace || ''}${txt}${p.postSpace || ''}`; // restore spaces
|
|
89
|
+
})
|
|
90
|
+
.join('');
|
|
91
|
+
|
|
92
|
+
return { key, idx, mainIdx, prefix, value: resultValue || value };
|
|
62
93
|
} catch (err) {
|
|
63
94
|
console.warn('translation request failed', err.toString());
|
|
64
|
-
return { key, idx, prefix, value, error: err.toString() }; // fallback
|
|
95
|
+
return { key, idx, mainIdx, prefix, value, error: err.toString() }; // fallback
|
|
65
96
|
}
|
|
66
97
|
})
|
|
67
98
|
);
|
|
68
99
|
|
|
69
|
-
const result = translatedPhrases.reduce((acc,
|
|
70
|
-
|
|
100
|
+
const result = translatedPhrases.reduce((acc, curr) => {
|
|
101
|
+
const { key, idx, prefix: prefix1, value, mainIdx } = curr;
|
|
102
|
+
const [prefix, subkey] = prefix1.split('.');
|
|
103
|
+
|
|
104
|
+
if (!acc[`${prefix}:${to}`]) {
|
|
105
|
+
acc[`${prefix}:${to}`] = Array.isArray(entries.find(e => e[0] === prefix)[1]) ? [] : null;
|
|
106
|
+
}
|
|
71
107
|
|
|
72
|
-
if (Array.isArray(entries.find(e => e[0] === prefix)[1])) {
|
|
73
|
-
if (!acc[`${prefix}:${to}`][
|
|
108
|
+
if (subkey && Array.isArray(entries.find(e => e[0] === prefix)[1])) {
|
|
109
|
+
if (!acc[`${prefix}:${to}`][mainIdx]) {
|
|
110
|
+
acc[`${prefix}:${to}`][mainIdx] = {};
|
|
111
|
+
}
|
|
112
|
+
if (!acc[`${prefix}:${to}`][mainIdx][subkey]) {
|
|
113
|
+
acc[`${prefix}:${to}`][mainIdx][subkey] = [];
|
|
114
|
+
}
|
|
115
|
+
if (!acc[`${prefix}:${to}`][mainIdx][subkey]?.[idx]) {
|
|
116
|
+
acc[`${prefix}:${to}`][mainIdx][subkey][idx] = {};
|
|
117
|
+
}
|
|
118
|
+
acc[`${prefix}:${to}`][mainIdx][subkey][idx][key] = value;
|
|
119
|
+
// console.log(prefix, to, idx, subkey, mainIdx, key);
|
|
120
|
+
} else if (Array.isArray(entries.find(e => e[0] === prefix)[1])) {
|
|
121
|
+
if (!acc[`${prefix}:${to}`][idx]) {
|
|
122
|
+
acc[`${prefix}:${to}`][idx] = {};
|
|
123
|
+
}
|
|
74
124
|
acc[`${prefix}:${to}`][idx][key] = value;
|
|
75
125
|
} else {
|
|
76
126
|
acc[`${prefix}:${to}`] = value;
|
|
@@ -14,16 +14,11 @@ export default async function updateLocalization(pg, id, body, contentTypeId, ui
|
|
|
14
14
|
|
|
15
15
|
const columns = (loadTable?.columns || []).concat((contentColumns || []).filter(col => loadTable?.columns.findIndex(el => el.name === col.name) === -1));
|
|
16
16
|
|
|
17
|
-
const locales = await pg.query('select locales from site.spaces where space_id = $1 limit 1', ['default']).then(el => el.rows?.[0]?.locales || []);
|
|
18
|
-
|
|
19
17
|
await pg.query('delete from site.localization where object_id=$1', [id]);
|
|
20
18
|
|
|
21
|
-
// localization disable for current space
|
|
22
|
-
if (!locales?.length) { return null; }
|
|
23
|
-
|
|
24
19
|
const schemaKeys = columns.filter(el => el?.name && el.localization).map(el => el.name);
|
|
25
20
|
|
|
26
|
-
const bodyKeys = Object.keys(body || {}).filter(key => body[key] && key.includes(':') && key.split(':').pop() &&
|
|
21
|
+
const bodyKeys = Object.keys(body || {}).filter(key => body[key] && key.includes(':') && key.split(':').pop() && schemaKeys.includes(key.split(':').shift()));
|
|
27
22
|
const obj = bodyKeys.reduce((acc, curr) => ({ ...acc, [curr]: body[curr] }), {});
|
|
28
23
|
|
|
29
24
|
if (bodyKeys.length === 0) { return null; }
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { dataDelete, pgClients } from '@opengis/fastify-table/utils.js';
|
|
2
2
|
|
|
3
3
|
export default async function deleteSpace({ pg = pgClients.client, user, params, headers = {} }, reply) {
|
|
4
|
+
return null;
|
|
4
5
|
if (!params?.id) { return reply.status(400).send('not enough params: id'); }
|
|
5
6
|
if (!pg?.pk) { return reply.status(400).send('empty pg'); }
|
|
6
7
|
if (!pg?.pk?.['site.spaces']) { return reply.status(400).send('table not found: site.spaces'); }
|
|
@@ -4,6 +4,7 @@ const maxLimit = 100;
|
|
|
4
4
|
const defaultLimit = 20;
|
|
5
5
|
|
|
6
6
|
export default async function getSpaces({ pg = pgClients.client, user, params = {}, query = {} }, reply) {
|
|
7
|
+
return null;
|
|
7
8
|
if (!pg?.pk) { return reply.status(400).send('empty pg'); }
|
|
8
9
|
if (!pg?.pk?.['site.spaces']) { return reply.status(400).send('table not found: site.spaces'); }
|
|
9
10
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { dataInsert, pgClients } from '@opengis/fastify-table/utils.js';
|
|
2
2
|
|
|
3
3
|
export default async function insertSpace({ pg = pgClients.client, user, params, headers = {}, body = {} }, reply) {
|
|
4
|
+
return null;
|
|
4
5
|
if (!pg?.pk) { return reply.status(400).send('empty pg'); }
|
|
5
6
|
if (!pg?.pk?.['site.spaces']) { return reply.status(400).send('table not found: site.spaces'); }
|
|
6
7
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { dataUpdate, pgClients } from '@opengis/fastify-table/utils.js';
|
|
2
2
|
|
|
3
3
|
export default async function updateSpace({ pg = pgClients.client, user, params, headers = {}, body = {} }, reply) {
|
|
4
|
+
return null;
|
|
4
5
|
// if (!params?.id) { return reply.status(400).send('not enough params: id'); }
|
|
5
6
|
if (!pg?.pk) { return reply.status(400).send('empty pg'); }
|
|
6
7
|
if (!pg?.pk?.['site.spaces']) { return reply.status(400).send('table not found: site.spaces'); }
|