@opengis/cms 0.0.13 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/ArticlesPage-BveM4q3g.js +11 -0
- package/dist/assets/CollectionsPage-D5td-UBm.js +1 -0
- package/dist/assets/ContentBlock.vue_vue_type_script_setup_true_lang-BwF6D-yB.js +30 -0
- package/dist/assets/CreateCollectionPage-Cu0RW5ui.js +76 -0
- package/dist/assets/Dashboard-faSjwmB8.js +11 -0
- package/dist/assets/EditCollectionPage-K5oPPzCd.js +1 -0
- package/dist/assets/MediaPage-BoW3aWgN.js +1 -0
- package/dist/assets/PermissionsPage-DGy5fha2.js +1 -0
- package/dist/assets/SingletonsPage-C1X2xkQE.js +1 -0
- package/dist/assets/UniversalTable.vue_vue_type_script_setup_true_lang-DUqfWJcy.js +6 -0
- package/dist/assets/calendar-hsWc4yH-.js +6 -0
- package/dist/assets/contentForm-DMVC4vho.js +1 -0
- package/dist/assets/database-BTxZQzYy.js +6 -0
- package/dist/assets/index-9GY17iSP.css +1 -0
- package/dist/assets/index-DYyZmLWO.js +2138 -0
- package/dist/assets/index-xsH4HHeE.js +6 -0
- package/dist/assets/logo-Cct5WB26.png +0 -0
- package/dist/assets/plus-D9etvrM2.js +6 -0
- package/dist/assets/save-C2B6th9J.js +11 -0
- package/dist/assets/search-BI-hqhq6.js +6 -0
- package/dist/assets/settings-DbyDiH2g.js +6 -0
- package/dist/assets/square-pen-61CkyXzK.js +6 -0
- package/dist/assets/trash-2-CJSl_r88.js +6 -0
- package/dist/assets/vue.-sixQ7xP-DwXf3zRn.js +1 -0
- package/dist/assets/x-BNquQe5y.js +6 -0
- package/dist/assets/x-circle-C3q70RMH.js +16 -0
- package/dist/images/logo.png +0 -0
- package/dist/index.html +30 -0
- package/package.json +38 -32
- package/server/app.js +32 -10
- package/server/index.js +3 -3
- package/server/migrations/site.sql +26 -8
- package/server/plugins/adminHook.js +78 -0
- package/server/plugins/hook.js +54 -78
- package/server/plugins/vite.js +13 -9
- package/server/routes/cms/controllers/deleteContent.js +60 -0
- package/server/routes/{site → cms}/controllers/deleteMedia.js +46 -46
- package/server/routes/{site → cms}/controllers/downloadMedia.js +48 -48
- package/server/routes/cms/controllers/getContent.js +96 -0
- package/server/routes/{site → cms}/controllers/getPermissions.js +15 -15
- package/server/routes/cms/controllers/insertContent.js +69 -0
- package/server/routes/{site → cms}/controllers/listMedia.js +72 -72
- package/server/routes/{site → cms}/controllers/metadataMedia.js +37 -37
- package/server/routes/{site → cms}/controllers/setPermissions.js +49 -49
- package/server/routes/cms/controllers/updateContent.js +112 -0
- package/server/routes/{site → cms}/controllers/uploadMedia.js +65 -65
- package/server/routes/cms/index.mjs +45 -0
- package/server/routes/contentType/controllers/cms.type.delete.js +22 -0
- package/server/routes/contentType/controllers/cms.type.get.js +22 -0
- package/server/routes/contentType/controllers/cms.type.list.js +25 -0
- package/server/routes/contentType/controllers/cms.type.post.js +22 -0
- package/server/routes/contentType/controllers/cms.type.put.js +24 -0
- package/server/routes/contentType/index.mjs +25 -0
- package/server/routes/contentType/utils/builderCache.js +58 -0
- package/server/routes/fileContent/data/deleteContent.js +34 -0
- package/server/routes/fileContent/data/deleteMedia.js +28 -0
- package/server/routes/fileContent/data/downloadMedia.js +41 -0
- package/server/routes/fileContent/data/getContent.js +32 -0
- package/server/routes/fileContent/data/insertContent.js +37 -0
- package/server/routes/fileContent/data/listMedia.js +47 -0
- package/server/routes/fileContent/data/metadataMedia.js +38 -0
- package/server/routes/fileContent/data/updateContent.js +40 -0
- package/server/routes/fileContent/data/uploadMedia.js +49 -0
- package/server/routes/fileContent/index.mjs +54 -0
- package/server/routes/fileContent/type/contentTypeList.js +7 -0
- package/server/routes/fileContent/type/createContentType.js +31 -0
- package/server/routes/fileContent/type/deleteContentType.js +29 -0
- package/server/routes/fileContent/type/getContentType.js +15 -0
- package/server/routes/fileContent/type/updateContentType.js +40 -0
- package/server/routes/fileContent/utils/astroBuilderCache.js +47 -0
- package/server/routes/fileContent/utils/contentDir.js +12 -0
- package/server/routes/fileContent/utils/contentTypeExists.js +15 -0
- package/server/routes/root.mjs +0 -7
- package/dist/cms.js +0 -6727
- package/dist/cms.umd.cjs +0 -19
- package/dist/style.css +0 -1
- package/server/routes/builder/controllers/cms.builder.delete.js +0 -21
- package/server/routes/builder/controllers/cms.builder.get.js +0 -17
- package/server/routes/builder/controllers/cms.builder.list.js +0 -16
- package/server/routes/builder/controllers/cms.builder.post.js +0 -21
- package/server/routes/builder/controllers/cms.builder.put.js +0 -23
- package/server/routes/builder/index.mjs +0 -22
- package/server/routes/manager/controllers/cms.manager.delete.js +0 -22
- package/server/routes/manager/controllers/cms.manager.get.js +0 -21
- package/server/routes/manager/controllers/cms.manager.list.js +0 -31
- package/server/routes/manager/controllers/cms.manager.post.js +0 -28
- package/server/routes/manager/controllers/cms.manager.put.js +0 -23
- package/server/routes/manager/index.mjs +0 -22
- package/server/routes/media/controllers/delete.js +0 -59
- package/server/routes/media/controllers/edit.js +0 -94
- package/server/routes/media/controllers/list.js +0 -74
- package/server/routes/media/controllers/metadata.js +0 -51
- package/server/routes/media/controllers/preview.js +0 -47
- package/server/routes/media/controllers/upload.js +0 -79
- package/server/routes/media/index.mjs +0 -16
- package/server/routes/site/index.mjs +0 -34
|
@@ -1,73 +1,73 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import { existsSync, mkdirSync } from 'node:fs';
|
|
3
|
-
import { readdir, stat } from 'node:fs/promises';
|
|
4
|
-
|
|
5
|
-
import { config, getFolder, pgClients } from '@opengis/fastify-table/utils.js';
|
|
6
|
-
|
|
7
|
-
const rootDir = getFolder(config, 'local');
|
|
8
|
-
mkdirSync(path.join(rootDir, 'media'), { recursive: true });
|
|
9
|
-
|
|
10
|
-
export default async function listMedia(req, reply) {
|
|
11
|
-
const { pg = pgClients.client, query = {} } = req;
|
|
12
|
-
const { subdir = '' } = query;
|
|
13
|
-
|
|
14
|
-
if (!pg.pk?.['site.media']) {
|
|
15
|
-
return reply.status(404).send('table not found');
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
if (typeof subdir !== 'string' || subdir.includes('..')) {
|
|
19
|
-
return reply.status(403).send('invalid params: subdir');
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const relpath = path.join('/media', subdir).replace(/\\/g, '/');
|
|
23
|
-
const dirpath = path.join(rootDir, relpath).replace(/\\/g, '/');
|
|
24
|
-
|
|
25
|
-
if (!existsSync(dirpath)) {
|
|
26
|
-
return { data: [], relpath, msg: 'directory not exists' };
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const { rows = [] } = await pg.query(
|
|
30
|
-
`select
|
|
31
|
-
media_id as id, filename, filetype, filesize, url, description, alt,
|
|
32
|
-
mime, preview_url, created_at, updated_at, created_by, updated_by
|
|
33
|
-
from site.media
|
|
34
|
-
where url ~ $1`,
|
|
35
|
-
[relpath],
|
|
36
|
-
);
|
|
37
|
-
|
|
38
|
-
const isDirectory = (await stat(dirpath)).isDirectory();
|
|
39
|
-
|
|
40
|
-
const items = isDirectory ? await readdir(dirpath, { withFileTypes: true }) : [];
|
|
41
|
-
|
|
42
|
-
const subdirs = items
|
|
43
|
-
.filter(el => el.isDirectory())
|
|
44
|
-
.map(el => ({ type: 'dir', name: el.name }));
|
|
45
|
-
|
|
46
|
-
if (subdirs.length) {
|
|
47
|
-
await Promise.all(subdirs.map(async (item) => {
|
|
48
|
-
const items = isDirectory ? await readdir(path.join(dirpath, item.name)) : [];
|
|
49
|
-
Object.assign(item, { count: items.length });
|
|
50
|
-
}));
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const result = { relpath, data: rows.concat(subdirs) };
|
|
54
|
-
|
|
55
|
-
if (config.debug) {
|
|
56
|
-
Object.assign(result, { rootDir });
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (!rows.length) {
|
|
60
|
-
return result;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
rows.forEach(row => Object.assign(row, {
|
|
64
|
-
type: 'file',
|
|
65
|
-
url: `${req.routeOptions.url}/${row.id}/file`,
|
|
66
|
-
filepath: row.url,
|
|
67
|
-
name: row.filename,
|
|
68
|
-
metadata: `${req.routeOptions.url}/${row.id}`,
|
|
69
|
-
exists: !!items.find(el => el.isFile() && el.name === path.basename(row.url))
|
|
70
|
-
}));
|
|
71
|
-
|
|
72
|
-
return result;
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { existsSync, mkdirSync } from 'node:fs';
|
|
3
|
+
import { readdir, stat } from 'node:fs/promises';
|
|
4
|
+
|
|
5
|
+
import { config, getFolder, pgClients } from '@opengis/fastify-table/utils.js';
|
|
6
|
+
|
|
7
|
+
const rootDir = getFolder(config, 'local');
|
|
8
|
+
mkdirSync(path.join(rootDir, 'media'), { recursive: true });
|
|
9
|
+
|
|
10
|
+
export default async function listMedia(req, reply) {
|
|
11
|
+
const { pg = pgClients.client, query = {} } = req;
|
|
12
|
+
const { subdir = '' } = query;
|
|
13
|
+
|
|
14
|
+
if (!pg.pk?.['site.media']) {
|
|
15
|
+
return reply.status(404).send('table not found');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (typeof subdir !== 'string' || subdir.includes('..')) {
|
|
19
|
+
return reply.status(403).send('invalid params: subdir');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const relpath = path.join('/media', subdir).replace(/\\/g, '/');
|
|
23
|
+
const dirpath = path.join(rootDir, relpath).replace(/\\/g, '/');
|
|
24
|
+
|
|
25
|
+
if (!existsSync(dirpath)) {
|
|
26
|
+
return { data: [], relpath, msg: 'directory not exists' };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const { rows = [] } = await pg.query(
|
|
30
|
+
`select
|
|
31
|
+
media_id as id, filename, filetype, filesize, url, description, alt,
|
|
32
|
+
mime, preview_url, created_at, updated_at, created_by, updated_by
|
|
33
|
+
from site.media
|
|
34
|
+
where url ~ $1`,
|
|
35
|
+
[relpath],
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
const isDirectory = (await stat(dirpath)).isDirectory();
|
|
39
|
+
|
|
40
|
+
const items = isDirectory ? await readdir(dirpath, { withFileTypes: true }) : [];
|
|
41
|
+
|
|
42
|
+
const subdirs = items
|
|
43
|
+
.filter(el => el.isDirectory())
|
|
44
|
+
.map(el => ({ type: 'dir', name: el.name }));
|
|
45
|
+
|
|
46
|
+
if (subdirs.length) {
|
|
47
|
+
await Promise.all(subdirs.map(async (item) => {
|
|
48
|
+
const items = isDirectory ? await readdir(path.join(dirpath, item.name)) : [];
|
|
49
|
+
Object.assign(item, { count: items.length });
|
|
50
|
+
}));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const result = { relpath, data: rows.concat(subdirs) };
|
|
54
|
+
|
|
55
|
+
if (config.debug) {
|
|
56
|
+
Object.assign(result, { rootDir });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (!rows.length) {
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
rows.forEach(row => Object.assign(row, {
|
|
64
|
+
type: 'file',
|
|
65
|
+
url: `${req.routeOptions.url}/${row.id}/file`,
|
|
66
|
+
filepath: row.url,
|
|
67
|
+
name: row.filename,
|
|
68
|
+
metadata: `${req.routeOptions.url}/${row.id}`,
|
|
69
|
+
exists: !!items.find(el => el.isFile() && el.name === path.basename(row.url))
|
|
70
|
+
}));
|
|
71
|
+
|
|
72
|
+
return result;
|
|
73
73
|
}
|
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import { existsSync } from 'node:fs';
|
|
3
|
-
|
|
4
|
-
import { config, getFolder, pgClients } from "@opengis/fastify-table/utils.js";
|
|
5
|
-
|
|
6
|
-
const rootDir = getFolder(config, 'local');
|
|
7
|
-
|
|
8
|
-
export default async function metadataMedia({
|
|
9
|
-
routeOptions = {}, pg = pgClients.client, params = {},
|
|
10
|
-
}, reply) {
|
|
11
|
-
if (!params?.id) {
|
|
12
|
-
return reply.status(400).send('not enough params: id');
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
if (!pg.pk?.['site.media']) {
|
|
16
|
-
return reply.status(404).send('table not found');
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const data = await pg.query(
|
|
20
|
-
'select * from site.media where media_id = $1 and url is not null',
|
|
21
|
-
[params.id],
|
|
22
|
-
).then(el => el.rows?.[0]);
|
|
23
|
-
|
|
24
|
-
if (!data) {
|
|
25
|
-
return reply.status(404).send('media not found: ' + params.id);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const filepath = path.join(rootDir, data.url);
|
|
29
|
-
|
|
30
|
-
Object.assign(data, {
|
|
31
|
-
url: `${routeOptions.url.replace(':id', params.id)}/file`,
|
|
32
|
-
filepath: data.url,
|
|
33
|
-
exists: existsSync(filepath),
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
return reply.status(200).send(data);
|
|
37
|
-
}
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
|
|
4
|
+
import { config, getFolder, pgClients } from "@opengis/fastify-table/utils.js";
|
|
5
|
+
|
|
6
|
+
const rootDir = getFolder(config, 'local');
|
|
7
|
+
|
|
8
|
+
export default async function metadataMedia({
|
|
9
|
+
routeOptions = {}, pg = pgClients.client, params = {},
|
|
10
|
+
}, reply) {
|
|
11
|
+
if (!params?.id) {
|
|
12
|
+
return reply.status(400).send('not enough params: id');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (!pg.pk?.['site.media']) {
|
|
16
|
+
return reply.status(404).send('table not found');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const data = await pg.query(
|
|
20
|
+
'select * from site.media where media_id = $1 and url is not null',
|
|
21
|
+
[params.id],
|
|
22
|
+
).then(el => el.rows?.[0]);
|
|
23
|
+
|
|
24
|
+
if (!data) {
|
|
25
|
+
return reply.status(404).send('media not found: ' + params.id);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const filepath = path.join(rootDir, data.url);
|
|
29
|
+
|
|
30
|
+
Object.assign(data, {
|
|
31
|
+
url: `${routeOptions.url.replace(':id', params.id)}/file`,
|
|
32
|
+
filepath: data.url,
|
|
33
|
+
exists: existsSync(filepath),
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
return reply.status(200).send(data);
|
|
37
|
+
}
|
|
@@ -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
|
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { config, pgClients, dataUpdate, dataInsert } from '@opengis/fastify-table/utils.js';
|
|
2
|
+
|
|
3
|
+
import builderCache from '../../contentType/utils/builderCache.js';
|
|
4
|
+
|
|
5
|
+
export default async function updateContent(req, reply) {
|
|
6
|
+
const {
|
|
7
|
+
pg = pgClients.client,
|
|
8
|
+
params = {},
|
|
9
|
+
user = {},
|
|
10
|
+
body = {},
|
|
11
|
+
headers = {},
|
|
12
|
+
} = req;
|
|
13
|
+
|
|
14
|
+
const { type, id } = params;
|
|
15
|
+
|
|
16
|
+
if (!type) {
|
|
17
|
+
return reply.status(400).send('not enough params: type');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (!id) {
|
|
21
|
+
return reply.status(400).send('not enough params: id');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (!Object.keys(body || {}).length) {
|
|
25
|
+
return reply.status(400).send('empty body');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (type === 'single') {
|
|
29
|
+
const cache = builderCache(id) || {};
|
|
30
|
+
if (!cache) {
|
|
31
|
+
return reply.status(400).send('invalid params: id');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const client = await pg.connect();
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
await client.query('BEGIN');
|
|
38
|
+
// await client.query('SET statement_timeout = 100000000;');
|
|
39
|
+
await client.query(`delete from site.single_type_values where type_name=$1`, [id]);
|
|
40
|
+
|
|
41
|
+
await Promise.all(Object.keys(body).filter(key => body[key]).map(async key => dataInsert({
|
|
42
|
+
pg: client,
|
|
43
|
+
table: 'site.single_type_values',
|
|
44
|
+
data: { key, value: body[key], type_name: id },
|
|
45
|
+
referer: headers?.referer,
|
|
46
|
+
uid: user?.uid || 0,
|
|
47
|
+
})));
|
|
48
|
+
|
|
49
|
+
// await client.query('SET statement_timeout = 0;');
|
|
50
|
+
|
|
51
|
+
await client.query('COMMIT');
|
|
52
|
+
return reply.status(200).send({ id, ...body });
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
await client.query('ROLLBACK');
|
|
56
|
+
return reply.status(500).send(err.toString());
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
client.release();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (builderCache[type]?.table && builderCache[type]?.provider === 'pg' && config.pg) {
|
|
64
|
+
const result = await dataUpdate({
|
|
65
|
+
pg,
|
|
66
|
+
id,
|
|
67
|
+
table: 'site.' + builderCache[type]?.table,
|
|
68
|
+
data: body,
|
|
69
|
+
referer: headers?.referer,
|
|
70
|
+
uid: user?.uid || 0,
|
|
71
|
+
}).catch(err => {
|
|
72
|
+
if (err.message?.includes?.('unique constraint')) {
|
|
73
|
+
return reply.status(400).send('Порушенні унікальності: ' + err.message?.match?.(/([^"]+)/g)?.[1]);
|
|
74
|
+
}
|
|
75
|
+
return reply.status(500).send(err.toString());
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const pk = pg.pk?.['site.' + builderCache[type]?.table];
|
|
79
|
+
return reply.status(200).send({ id: result?.[pk], ...result || {} });
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const arr = config.pg ? await pg.query(`select array_agg(relname)::text[] from pg_class a
|
|
83
|
+
left join pg_namespace b on a.relnamespace=b.oid
|
|
84
|
+
where a.relam=2 and b.nspname='site'`).then(el => el.rows?.[0]?.array_agg || []) : [];
|
|
85
|
+
|
|
86
|
+
if (!arr.length) {
|
|
87
|
+
return reply.status(400).send('empty schema: site');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const table = arr.find(el => el === params.type);
|
|
91
|
+
|
|
92
|
+
if (!table) {
|
|
93
|
+
return reply.status(400).send('invalid params: type');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const result = await dataUpdate({
|
|
97
|
+
pg,
|
|
98
|
+
id,
|
|
99
|
+
table: 'site.' + table,
|
|
100
|
+
data: body,
|
|
101
|
+
referer: headers?.referer,
|
|
102
|
+
uid: user?.uid || 0,
|
|
103
|
+
}).catch(err => {
|
|
104
|
+
if (err.message?.includes?.('unique constraint')) {
|
|
105
|
+
return reply.status(400).send('Порушенні унікальності: ' + err.message?.match?.(/([^"]+)/g)?.[1]);
|
|
106
|
+
}
|
|
107
|
+
return reply.status(500).send(err.toString());
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const pk = pg.pk?.['site.' + table];
|
|
111
|
+
return reply.status(200).send({ id: result?.[pk], ...result || {} });
|
|
112
|
+
}
|
|
@@ -1,66 +1,66 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import { mkdir, rename } from 'node:fs/promises';
|
|
3
|
-
|
|
4
|
-
import { config, getFolder, dataInsert, pgClients } from "@opengis/fastify-table/utils.js";
|
|
5
|
-
|
|
6
|
-
import { getMimeType, getFileType, uploadMultiPart } from '@opengis/fastify-file/utils.js';
|
|
7
|
-
import { existsSync } from 'node:fs';
|
|
8
|
-
|
|
9
|
-
const rootDir = getFolder(config, 'local');
|
|
10
|
-
|
|
11
|
-
export default async function uploadMedia(req, reply) {
|
|
12
|
-
const { pg = pgClients.client, user = {}, body = {}, query = {} } = req;
|
|
13
|
-
|
|
14
|
-
if (!pg.pk?.['site.media']) {
|
|
15
|
-
return reply.status(404).send('table not found');
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
if (query.subdir && (typeof query.subdir !== 'string' || query.subdir.includes('..'))) {
|
|
19
|
-
return reply.status(403).send('invalid query params: subdir');
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// upload assets
|
|
23
|
-
if (req.headers['content-type']?.split?.(';')?.shift?.() === 'multipart/form-data') {
|
|
24
|
-
const file = await uploadMultiPart(req);
|
|
25
|
-
const filename = `${file.newFilename}${path.extname(file.filepath)}`;
|
|
26
|
-
const mime = getMimeType(file.filepath);
|
|
27
|
-
const filetype = getFileType(file.filepath);
|
|
28
|
-
|
|
29
|
-
const newfilepath = path.join(rootDir, 'media', query.subdir || '', filename);
|
|
30
|
-
await mkdir(path.dirname(newfilepath), { recursive: true });
|
|
31
|
-
await rename(file.filepath, newfilepath);
|
|
32
|
-
|
|
33
|
-
const relpath = path.join('/media', query.subdir || '', filename).replace(/\\/g, '/');
|
|
34
|
-
const id = await dataInsert({
|
|
35
|
-
pg,
|
|
36
|
-
table: 'site.media',
|
|
37
|
-
data: {
|
|
38
|
-
filename: file.originalFilename,
|
|
39
|
-
filetype,
|
|
40
|
-
url: relpath,
|
|
41
|
-
mime,
|
|
42
|
-
filesize: file.size,
|
|
43
|
-
},
|
|
44
|
-
uid: user?.uid || 0,
|
|
45
|
-
}).then(el => el?.rows?.[0]?.media_id);
|
|
46
|
-
|
|
47
|
-
return reply.status(200).send({
|
|
48
|
-
relpath: path.join('/media', query.subdir || '').replace(/\\/g, '/'),
|
|
49
|
-
id,
|
|
50
|
-
filename,
|
|
51
|
-
filetype,
|
|
52
|
-
type: 'file',
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// create directory
|
|
57
|
-
const relpath = path.join('/media', query.subdir).replace(/\\/g, '/');
|
|
58
|
-
const dirpath = path.join(rootDir, relpath);
|
|
59
|
-
await mkdir(dirpath, { recursive: true });
|
|
60
|
-
|
|
61
|
-
return reply.status(200).send({
|
|
62
|
-
relpath,
|
|
63
|
-
dirname: path.basename(query.subdir),
|
|
64
|
-
type: 'dir',
|
|
65
|
-
});
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { mkdir, rename } from 'node:fs/promises';
|
|
3
|
+
|
|
4
|
+
import { config, getFolder, dataInsert, pgClients } from "@opengis/fastify-table/utils.js";
|
|
5
|
+
|
|
6
|
+
import { getMimeType, getFileType, uploadMultiPart } from '@opengis/fastify-file/utils.js';
|
|
7
|
+
import { existsSync } from 'node:fs';
|
|
8
|
+
|
|
9
|
+
const rootDir = getFolder(config, 'local');
|
|
10
|
+
|
|
11
|
+
export default async function uploadMedia(req, reply) {
|
|
12
|
+
const { pg = pgClients.client, user = {}, body = {}, query = {} } = req;
|
|
13
|
+
|
|
14
|
+
if (!pg.pk?.['site.media']) {
|
|
15
|
+
return reply.status(404).send('table not found');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (query.subdir && (typeof query.subdir !== 'string' || query.subdir.includes('..'))) {
|
|
19
|
+
return reply.status(403).send('invalid query params: subdir');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// upload assets
|
|
23
|
+
if (req.headers['content-type']?.split?.(';')?.shift?.() === 'multipart/form-data') {
|
|
24
|
+
const file = await uploadMultiPart(req);
|
|
25
|
+
const filename = `${file.newFilename}${path.extname(file.filepath)}`;
|
|
26
|
+
const mime = getMimeType(file.filepath);
|
|
27
|
+
const filetype = getFileType(file.filepath);
|
|
28
|
+
|
|
29
|
+
const newfilepath = path.join(rootDir, 'media', query.subdir || '', filename);
|
|
30
|
+
await mkdir(path.dirname(newfilepath), { recursive: true });
|
|
31
|
+
await rename(file.filepath, newfilepath);
|
|
32
|
+
|
|
33
|
+
const relpath = path.join('/media', query.subdir || '', filename).replace(/\\/g, '/');
|
|
34
|
+
const id = await dataInsert({
|
|
35
|
+
pg,
|
|
36
|
+
table: 'site.media',
|
|
37
|
+
data: {
|
|
38
|
+
filename: file.originalFilename,
|
|
39
|
+
filetype,
|
|
40
|
+
url: relpath,
|
|
41
|
+
mime,
|
|
42
|
+
filesize: file.size,
|
|
43
|
+
},
|
|
44
|
+
uid: user?.uid || 0,
|
|
45
|
+
}).then(el => el?.rows?.[0]?.media_id);
|
|
46
|
+
|
|
47
|
+
return reply.status(200).send({
|
|
48
|
+
relpath: path.join('/media', query.subdir || '').replace(/\\/g, '/'),
|
|
49
|
+
id,
|
|
50
|
+
filename,
|
|
51
|
+
filetype,
|
|
52
|
+
type: 'file',
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// create directory
|
|
57
|
+
const relpath = path.join('/media', query.subdir).replace(/\\/g, '/');
|
|
58
|
+
const dirpath = path.join(rootDir, relpath);
|
|
59
|
+
await mkdir(dirpath, { recursive: true });
|
|
60
|
+
|
|
61
|
+
return reply.status(200).send({
|
|
62
|
+
relpath,
|
|
63
|
+
dirname: path.basename(query.subdir),
|
|
64
|
+
type: 'dir',
|
|
65
|
+
});
|
|
66
66
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
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 insertContent from './controllers/insertContent.js';
|
|
15
|
+
import updateContent from './controllers/updateContent.js';
|
|
16
|
+
import deleteContent from './controllers/deleteContent.js';
|
|
17
|
+
|
|
18
|
+
const schemaObj = {
|
|
19
|
+
type: 'object',
|
|
20
|
+
properties: {
|
|
21
|
+
params: {
|
|
22
|
+
type: 'string',
|
|
23
|
+
enum: ['preview', 'download'],
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const params = { config: { policy: ['public'] } };
|
|
29
|
+
|
|
30
|
+
export default async function route(app) {
|
|
31
|
+
app.post('/cms-permissions/:id', params, setPermissions);
|
|
32
|
+
app.get('/cms-permissions/:id?', params, getPermissions);
|
|
33
|
+
|
|
34
|
+
app.post('/cms-media/upload', params, uploadMedia);
|
|
35
|
+
app.get('/cms-media', params, listMedia);
|
|
36
|
+
app.get('/cms-media/:id/file', { ...params, schema: schemaObj }, download);
|
|
37
|
+
app.get('/cms-media/:id', params, metadata);
|
|
38
|
+
app.delete('/cms-media/:id', params, del);
|
|
39
|
+
app.get('/cms-media/:id/delete', params, del); // debug
|
|
40
|
+
|
|
41
|
+
app.get('/cms/:type/:id?', params, getContent);
|
|
42
|
+
app.post('/cms/:type/:id?', params, insertContent);
|
|
43
|
+
app.put('/cms/:type/:id', params, updateContent);
|
|
44
|
+
app.delete('/cms/:type/:id', params, deleteContent);
|
|
45
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { dataDelete, getMeta, pgClients } from '@opengis/fastify-table/utils.js';
|
|
2
|
+
|
|
3
|
+
export default async function builderDelete({ pg = pgClients.client, user = {}, params = {} }, reply) {
|
|
4
|
+
if (!params.id) {
|
|
5
|
+
return reply.status(400).send('not enough params: id');
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const { pk } = await getMeta({ pg, table: 'site.content_types' });
|
|
9
|
+
|
|
10
|
+
if (!pk) {
|
|
11
|
+
return reply.status(404).send('table not found');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const res = await dataDelete({
|
|
15
|
+
pg,
|
|
16
|
+
table: 'site.content_types',
|
|
17
|
+
id: params.id,
|
|
18
|
+
uid: user?.uid
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
return { id: res.content_id, rows: [res] };
|
|
22
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { pgClients, getMeta } from '@opengis/fastify-table/utils.js';
|
|
2
|
+
|
|
3
|
+
import cache from '../utils/builderCache.js';
|
|
4
|
+
|
|
5
|
+
export default async function builderGet({ pg = pgClients.client, params = {} }, reply) {
|
|
6
|
+
if (!params.id) {
|
|
7
|
+
return reply.status(400).send('not enough params: id');
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const { pk } = await getMeta({ pg, table: 'site.content_types' });
|
|
11
|
+
|
|
12
|
+
if (cache[params.id]) {
|
|
13
|
+
return reply.status(200).send({ total: 1, rows: [cache[params.id]] });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const { rows = [], rowCount: total = 0 } = pk ? await pg.query(
|
|
17
|
+
`select a.content_type_id as id, a.* FROM site.content_types a
|
|
18
|
+
where a.content_type_id=$1`, [params.id]
|
|
19
|
+
) : {};
|
|
20
|
+
|
|
21
|
+
return reply.status(200).send({ total, rows });
|
|
22
|
+
}
|