@opengis/cms 0.0.14 → 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 +13 -7
- package/server/plugins/adminHook.js +78 -0
- package/server/plugins/hook.js +54 -78
- package/server/plugins/vite.js +13 -9
- package/server/routes/{site → cms}/controllers/deleteContent.js +59 -44
- 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/{site → cms}/controllers/insertContent.js +68 -47
- 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/{site → cms}/index.mjs +13 -13
- 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/controllers/getContent.js +0 -43
- package/server/routes/site/controllers/updateContent.js +0 -52
|
@@ -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
|
}
|
|
@@ -25,21 +25,21 @@ const schemaObj = {
|
|
|
25
25
|
}
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
const params = { config: { policy: ['
|
|
28
|
+
const params = { config: { policy: ['public'] } };
|
|
29
29
|
|
|
30
30
|
export default async function route(app) {
|
|
31
|
-
app.post('/
|
|
32
|
-
app.get('/
|
|
31
|
+
app.post('/cms-permissions/:id', params, setPermissions);
|
|
32
|
+
app.get('/cms-permissions/:id?', params, getPermissions);
|
|
33
33
|
|
|
34
|
-
app.post('/
|
|
35
|
-
app.get('/
|
|
36
|
-
app.get('/
|
|
37
|
-
app.get('/
|
|
38
|
-
app.delete('/
|
|
39
|
-
app.get('/
|
|
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
40
|
|
|
41
|
-
app.get('/
|
|
42
|
-
app.post('/
|
|
43
|
-
app.put('/
|
|
44
|
-
app.delete('/
|
|
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
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
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { config, pgClients, getMeta } from '@opengis/fastify-table/utils.js';
|
|
2
|
+
|
|
3
|
+
import builderCache from '../utils/builderCache.js';
|
|
4
|
+
|
|
5
|
+
export default async function builderList({ pg = pgClients.client, query = {} }, reply) {
|
|
6
|
+
|
|
7
|
+
const { pk } = await getMeta({ pg, table: 'site.content_types' });
|
|
8
|
+
|
|
9
|
+
if (config.cms?.provider === 'pg') {
|
|
10
|
+
const cache = builderCache();
|
|
11
|
+
return reply.status(200).send({ total: cache?.length, rows: cache });
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (!pk) {
|
|
15
|
+
return reply.status(404).send('table not found');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const q = `select a.content_type_id as id, a.name, a.title, a.description, a.table_name as table FROM site.content_types a
|
|
19
|
+
where ${query.content_type_id ? 'content_type_id=$1' : '1=1'}`
|
|
20
|
+
|
|
21
|
+
const { rows = [] } = pk ? await pg.query(q, [query.content_type_id].filter((el) => el)) : {};
|
|
22
|
+
rows.forEach(row => Object.assign(row, { provider: 'pg' }));
|
|
23
|
+
|
|
24
|
+
return reply.status(200).send({ total: rows.length, rows });
|
|
25
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { dataInsert, getMeta, pgClients } from "@opengis/fastify-table/utils.js";
|
|
2
|
+
|
|
3
|
+
export default async function builderPost(req, reply) {
|
|
4
|
+
const { pg = pgClients.client, user = {}, body = {} } = req;
|
|
5
|
+
|
|
6
|
+
const { pk } = await getMeta({ pg, table: 'site.content_types' });
|
|
7
|
+
|
|
8
|
+
if (!pk) {
|
|
9
|
+
return reply.status(404).send('table not found');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const resData = await dataInsert({
|
|
13
|
+
pg,
|
|
14
|
+
table: "site.content_types",
|
|
15
|
+
data: body,
|
|
16
|
+
uid: user?.uid,
|
|
17
|
+
});
|
|
18
|
+
// console.log(resData);
|
|
19
|
+
const res = resData?.rows?.[0];
|
|
20
|
+
|
|
21
|
+
return { id: res?.content_type_id, rows: [res].filter(Boolean) };
|
|
22
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { dataUpdate, getMeta, pgClients } from '@opengis/fastify-table/utils.js';
|
|
2
|
+
|
|
3
|
+
export default async function builderPut(req, reply) {
|
|
4
|
+
const { pg = pgClients.client, body = {}, params = {} } = req;
|
|
5
|
+
if (!params.id) {
|
|
6
|
+
return reply.status(400).send('not enough params: id');
|
|
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 resData = await dataUpdate({
|
|
15
|
+
pg,
|
|
16
|
+
table: 'site.content_types',
|
|
17
|
+
data: body,
|
|
18
|
+
id: params.id,
|
|
19
|
+
});
|
|
20
|
+
// console.log(resData)
|
|
21
|
+
const res = resData;
|
|
22
|
+
|
|
23
|
+
return { id: res.content_type_id, rows: [res].filter(Boolean) };
|
|
24
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import cmsTypeGet from './controllers/cms.type.get.js';
|
|
2
|
+
import cmsTypeList from './controllers/cms.type.list.js';
|
|
3
|
+
import cmsTypePut from './controllers/cms.type.put.js';
|
|
4
|
+
import cmsTypePost from './controllers/cms.type.post.js';
|
|
5
|
+
import cmsTypeDelete from './controllers/cms.type.delete.js';
|
|
6
|
+
|
|
7
|
+
const policy = ['public'];
|
|
8
|
+
|
|
9
|
+
export default async function route(app) {
|
|
10
|
+
// Type add
|
|
11
|
+
app.post('/cms-type', { config: { policy } }, cmsTypePost);
|
|
12
|
+
|
|
13
|
+
// Type edit
|
|
14
|
+
app.put('/cms-type/:id', { config: { policy } }, cmsTypePut);
|
|
15
|
+
|
|
16
|
+
// Type list
|
|
17
|
+
app.get('/cms', { config: { policy } }, cmsTypeList);
|
|
18
|
+
app.get('/cms-type', { config: { policy } }, cmsTypeList);
|
|
19
|
+
|
|
20
|
+
// Type get
|
|
21
|
+
app.get('/cms-type/:id', { config: { policy } }, cmsTypeGet);
|
|
22
|
+
|
|
23
|
+
// Type delete
|
|
24
|
+
app.delete('/cms-type/:id', { config: { policy } }, cmsTypeDelete);
|
|
25
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
3
|
+
|
|
4
|
+
import { subscribe } from '@parcel/watcher';
|
|
5
|
+
|
|
6
|
+
import { config, yml2json } from '@opengis/fastify-table/utils.js';
|
|
7
|
+
|
|
8
|
+
function parseYml(filepath) {
|
|
9
|
+
const name = path.basename(filepath, '.yml');
|
|
10
|
+
|
|
11
|
+
const yml = readFileSync(filepath, 'utf8');
|
|
12
|
+
const json = yml2json(yml);
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
[name]: {
|
|
16
|
+
...json,
|
|
17
|
+
name,
|
|
18
|
+
id: json?.type === 'single' ? name : undefined,
|
|
19
|
+
table: json?.type === 'single' ? undefined : name,
|
|
20
|
+
provider: json.provider || 'pg',
|
|
21
|
+
slug: json?.type === 'single' ? name : (json.slug || 'slug')
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const content = config.cms?.root && existsSync(config.cms?.root)
|
|
27
|
+
? readdirSync(config.cms?.root, { withFileTypes: true })
|
|
28
|
+
: [];
|
|
29
|
+
|
|
30
|
+
const files = content.filter(el => el.isFile() && path.extname(el.name) === '.yml');
|
|
31
|
+
|
|
32
|
+
const cache = files.reduce((acc, curr) => {
|
|
33
|
+
return { ...acc, ...parseYml(path.join(config.cms.root, curr.name)) };
|
|
34
|
+
}, {});
|
|
35
|
+
|
|
36
|
+
async function watchDirectory() {
|
|
37
|
+
await subscribe(config.cms.root, (err, events) => {
|
|
38
|
+
if (err) throw new Error(err.toString());
|
|
39
|
+
|
|
40
|
+
const { path: filepath, type } = events[0];
|
|
41
|
+
const name = path.basename(filepath, '.yml');
|
|
42
|
+
if (path.extname(filepath) === '.yml') {
|
|
43
|
+
if (type !== 'delete') { cache[name] = parseYml(filepath); }
|
|
44
|
+
if (type === 'delete') { delete cache[name]; }
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (config.cms?.root && config.local) {
|
|
50
|
+
watchDirectory();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export default function builderCache(name) {
|
|
54
|
+
if (name) {
|
|
55
|
+
return cache[name];
|
|
56
|
+
}
|
|
57
|
+
return Object.values(cache || {});
|
|
58
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { existsSync, rmSync } from 'node:fs';
|
|
3
|
+
|
|
4
|
+
import contentDir from '../utils/contentDir.js';
|
|
5
|
+
import contentTypeExists from '../utils/contentTypeExists.js';
|
|
6
|
+
|
|
7
|
+
export default async function deleteContent(req, reply) {
|
|
8
|
+
const { params = {} } = req;
|
|
9
|
+
const { type, id } = params;
|
|
10
|
+
|
|
11
|
+
if (!type) {
|
|
12
|
+
return reply.status(400).send('not enough params: type');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (!id) {
|
|
16
|
+
return reply.status(400).send('not enough params: id');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (!contentTypeExists(type)) {
|
|
20
|
+
return reply.status(400).send('invalid params: type');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
const filepath = [path.join(contentDir, type, `${id}.mdoc`), path.join(contentDir, type, `${id}.md`)]
|
|
25
|
+
.find(el => existsSync(el));
|
|
26
|
+
|
|
27
|
+
if (!filepath) {
|
|
28
|
+
return reply.status(404).send('file not found');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
rmSync(filepath, { recursive: true });
|
|
32
|
+
|
|
33
|
+
return reply.status(200).send({ id, type, filepath });
|
|
34
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { existsSync, rmSync } from 'node:fs';
|
|
3
|
+
|
|
4
|
+
import { config, getFolder } from "@opengis/fastify-table/utils.js";
|
|
5
|
+
|
|
6
|
+
const rootDir = getFolder(config, 'local');
|
|
7
|
+
|
|
8
|
+
export default async function deleteMedia({
|
|
9
|
+
params = {},
|
|
10
|
+
}, reply) {
|
|
11
|
+
if (!params['*']) {
|
|
12
|
+
return reply.status(400).send('not enough params');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (typeof params['*'] !== 'string' || params['*'].includes('..')) {
|
|
16
|
+
return reply.status(403).send('invalid params');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const filepath = path.join(rootDir, params['*']);
|
|
20
|
+
|
|
21
|
+
if (!existsSync(filepath)) {
|
|
22
|
+
return reply.status(404).send('file not found');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
rmSync(filepath, { recursive: true });
|
|
26
|
+
|
|
27
|
+
return { filepath: params['*'] };
|
|
28
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
|
|
3
|
+
import { config, getFolder } from "@opengis/fastify-table/utils.js";
|
|
4
|
+
import { downloadFile, isFileExists, getMimeType } from '@opengis/fastify-file/utils.js';
|
|
5
|
+
|
|
6
|
+
const rootDir = getFolder(config, 'local');
|
|
7
|
+
|
|
8
|
+
export default async function downloadMedia({
|
|
9
|
+
params = {}, query = {},
|
|
10
|
+
}, reply) {
|
|
11
|
+
if (!params['*']) {
|
|
12
|
+
return reply.status(400).send('not enough params: id');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (typeof params['*'] !== 'string' || params['*'].includes('..')) {
|
|
16
|
+
return reply.status(403).send('invalid params');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const filepath = path.join(rootDir, params['*']);
|
|
20
|
+
|
|
21
|
+
const exists = await isFileExists(filepath);
|
|
22
|
+
|
|
23
|
+
if (!exists) {
|
|
24
|
+
return reply.status(404).send('file not found');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const buffer = await downloadFile(filepath, { buffer: true });
|
|
28
|
+
const mime = getMimeType(filepath);
|
|
29
|
+
|
|
30
|
+
// skip xml load for preview
|
|
31
|
+
if (query.preview && path.extname(filepath) !== '.xml') {
|
|
32
|
+
return reply.headers({ 'Content-Type': mime }).send(buffer);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return reply
|
|
36
|
+
.headers({
|
|
37
|
+
'Content-Type': mime,
|
|
38
|
+
'Content-Disposition': `attachment; filename=${path.basename(filepath)}`,
|
|
39
|
+
})
|
|
40
|
+
.send(buffer);
|
|
41
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { config } from '@opengis/fastify-table/utils.js';
|
|
2
|
+
|
|
3
|
+
import contentTypeExists from '../utils/contentTypeExists.js';
|
|
4
|
+
import { contentTypes } from '../utils/astroBuilderCache.js';
|
|
5
|
+
|
|
6
|
+
export default async function getContent(req, reply) {
|
|
7
|
+
const { params = {} } = req;
|
|
8
|
+
const { type, id } = params;
|
|
9
|
+
|
|
10
|
+
if (!type) {
|
|
11
|
+
return reply.status(400).send('not enough params: type');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const metadata = contentTypeExists(type, 'metadata.json');
|
|
15
|
+
|
|
16
|
+
if (!metadata) {
|
|
17
|
+
return reply.status(400).send('invalid params: type');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (!id) {
|
|
21
|
+
const rows = Object.values(contentTypes || {});
|
|
22
|
+
return { metadata, rows };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const data = contentTypeExists(type, id);
|
|
26
|
+
|
|
27
|
+
if (!data) {
|
|
28
|
+
return reply.status(404).send('file not found');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return { metadata, data };
|
|
32
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { writeFileSync } from 'node:fs';
|
|
3
|
+
|
|
4
|
+
import contentDir from '../utils/contentDir.js';
|
|
5
|
+
import contentTypeExists from '../utils/contentTypeExists.js';
|
|
6
|
+
|
|
7
|
+
const extension = 'mdoc'; // extract from collection?
|
|
8
|
+
|
|
9
|
+
export default async function insertContent(req, reply) {
|
|
10
|
+
const { params = {}, body = {} } = req;
|
|
11
|
+
const { slug, content } = body;
|
|
12
|
+
|
|
13
|
+
if (!params.type) {
|
|
14
|
+
return reply.status(400).send('not enough params: type');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (!slug) {
|
|
18
|
+
return reply.status(400).send('not enough body params: slug');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (!content) {
|
|
22
|
+
return reply.status(400).send('not enough body params: content');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (typeof content !== 'string') {
|
|
26
|
+
return reply.status(400).send('invalid params: content');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (!contentTypeExists(params.type)) {
|
|
30
|
+
return reply.status(400).send('invalid params: type');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const filepath = path.join(contentDir, params.type, `${slug}.${extension}`);
|
|
34
|
+
writeFileSync(filepath, content, { recursive: true });
|
|
35
|
+
|
|
36
|
+
return reply.status(200).send({ id: slug, type: params.type, filepath });
|
|
37
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
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 } 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 { query = {} } = req;
|
|
12
|
+
const { subdir = '' } = query;
|
|
13
|
+
|
|
14
|
+
if (typeof subdir !== 'string' || subdir.includes('..')) {
|
|
15
|
+
return reply.status(403).send('invalid params: subdir');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const relpath = path.join('/media', subdir).replace(/\\/g, '/');
|
|
19
|
+
const dirpath = path.join(rootDir, relpath).replace(/\\/g, '/');
|
|
20
|
+
|
|
21
|
+
if (!existsSync(dirpath)) {
|
|
22
|
+
return { data: [], relpath, msg: 'directory not exists' };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const isDirectory = (await stat(dirpath)).isDirectory();
|
|
26
|
+
|
|
27
|
+
const items = isDirectory ? await readdir(dirpath, { withFileTypes: true }) : [];
|
|
28
|
+
|
|
29
|
+
const content = items.map(el => ({ type: el.isDirectory() ? 'dir' : 'file', name: el.name }));
|
|
30
|
+
|
|
31
|
+
await Promise.all(content.filter(el => el.type === 'dir').map(async (item) => {
|
|
32
|
+
const items = await readdir(path.join(dirpath, item.name));
|
|
33
|
+
Object.assign(item, { count: items.length, exists: true });
|
|
34
|
+
}));
|
|
35
|
+
|
|
36
|
+
content.filter(el => el.type === 'file').forEach(item => {
|
|
37
|
+
item.exists = true;
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const result = { relpath, data: content };
|
|
41
|
+
|
|
42
|
+
if (config.debug) {
|
|
43
|
+
Object.assign(result, { rootDir });
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
|
|
4
|
+
import { config, getFolder } from "@opengis/fastify-table/utils.js";
|
|
5
|
+
import { stat } from 'node:fs/promises';
|
|
6
|
+
|
|
7
|
+
import downloadMedia from './downloadMedia.js';
|
|
8
|
+
|
|
9
|
+
const rootDir = getFolder(config, 'local');
|
|
10
|
+
|
|
11
|
+
export default async function metadataMedia(req, reply) {
|
|
12
|
+
if (!req.query?.metadata) return downloadMedia(req, reply);
|
|
13
|
+
|
|
14
|
+
const { params = {}, } = req;
|
|
15
|
+
|
|
16
|
+
if (!params['*']) {
|
|
17
|
+
return reply.status(400).send('not enough params: id');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (typeof params['*'] !== 'string' || params['*'].includes('..')) {
|
|
21
|
+
return reply.status(403).send('invalid params: subdir');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const filepath = path.join(rootDir, params['*']);
|
|
25
|
+
|
|
26
|
+
const stats = existsSync(filepath) ? await stat(filepath) : null;
|
|
27
|
+
|
|
28
|
+
if (!stats) {
|
|
29
|
+
return reply.status(404).send('file not found');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return reply.status(200).send({
|
|
33
|
+
...stats,
|
|
34
|
+
url: `${req.routeOptions.url}/${params['*']}?download=1`.replace(/\*/g, '').replace(/\/\//g, ''),
|
|
35
|
+
filepath: `${req.routeOptions.url}/${params['*']}`.replace(/\*/g, '').replace(/\/\//g, ''),
|
|
36
|
+
exists: true,
|
|
37
|
+
});
|
|
38
|
+
}
|