@opengis/cms 0.0.10 → 0.0.11
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/form-template-GUuvWUFU.js +1 -0
- package/dist/assets/icon-arrow-left-D8pa2IlJ.js +1 -0
- package/dist/assets/icon-check-CFkLh1zV.js +1 -0
- package/dist/assets/icon-chewron-right-GWQXirqc.js +1 -0
- package/dist/assets/icon-point-CS93fUI3.js +1 -0
- package/dist/assets/index-CAtBxNzW.js +10 -0
- package/dist/assets/index-qmYrZ9-m.js +2067 -0
- package/dist/assets/index-x9a62HSi.css +1 -0
- package/dist/assets/index-xsH4HHeE.js +6 -0
- package/dist/assets/vs-builder-UaCKb4IF.js +1 -0
- package/dist/assets/vs-builder-content-BCwIOG9K.js +1 -0
- package/dist/assets/vs-layout-De-zAhR4.js +1 -0
- package/dist/assets/vs-manager-collection-B_UcyvVB.js +1 -0
- package/dist/assets/vs-manager-collection-content-Dj40xY0r.js +1 -0
- package/dist/assets/vs-manager-collection-item-DkdSSkyR.js +1 -0
- package/dist/assets/vs-manager-collection-list-BIDZJyl4.js +1 -0
- package/dist/assets/vs-manager-single-content-DbVORsMN.js +1 -0
- package/dist/assets/vs-manager-single-vDpAZKAT.js +1 -0
- package/dist/assets/vs-media-DKX7riRI.js +1 -0
- package/dist/assets/vs-menu-tree-C4HFWvZd.js +1 -0
- package/dist/assets/vs-menu-tree-CF06sHhM.css +1 -0
- package/dist/assets/vs-not-data-B6bl0fjq.js +1 -0
- package/dist/assets/vs-permissions-CLUiqUH_.js +1 -0
- package/dist/index.html +15 -0
- package/package.json +5 -5
- package/server/app.js +5 -2
- package/server/migrations/site.sql +428 -0
- package/server/routes/site/controllers/deleteMedia.js +47 -0
- package/server/routes/site/controllers/downloadMedia.js +48 -0
- package/server/routes/site/controllers/getPermissions.js +16 -0
- package/server/routes/site/controllers/listMedia.js +60 -0
- package/server/routes/site/controllers/metadataMedia.js +37 -0
- package/server/routes/site/controllers/setPermissions.js +50 -0
- package/server/routes/site/controllers/uploadMedia.js +66 -0
- package/server/routes/site/index.mjs +34 -0
- package/dist/cms.js +0 -5900
- package/dist/cms.umd.cjs +0 -19
- package/server/migrations/media.sql +0 -30
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
|
|
5
|
+
import { config, getFolder, pgClients } from "@opengis/fastify-table/utils.js";
|
|
6
|
+
|
|
7
|
+
const rootDir = getFolder(config, 'local');
|
|
8
|
+
|
|
9
|
+
export default async function downloadMedia({
|
|
10
|
+
pg = pgClients.client, params = {}, query = {},
|
|
11
|
+
}, reply) {
|
|
12
|
+
if (!params?.id) {
|
|
13
|
+
return reply.status(400).send('not enough params: id');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (!pg.pk?.['site.media']) {
|
|
17
|
+
return reply.status(404).send('table not found');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const { filename, mime, id, url: relpath } = await pg.query(
|
|
21
|
+
'select media_id as id, filename, mime, url from site.media where media_id = $1 and url is not null',
|
|
22
|
+
[params.id],
|
|
23
|
+
).then(el => el.rows?.[0] || {});
|
|
24
|
+
|
|
25
|
+
if (!id) {
|
|
26
|
+
return reply.status(404).send('media not found: ' + params.id);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const filepath = path.join(rootDir, relpath);
|
|
30
|
+
|
|
31
|
+
if (!existsSync(filepath)) {
|
|
32
|
+
return reply.status(404).send('file not found');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const buffer = await readFile(filepath, { buffer: true });
|
|
36
|
+
|
|
37
|
+
// skip xml load for preview
|
|
38
|
+
if (query.preview && path.extname(filename) !== '.xml') {
|
|
39
|
+
return reply.headers({ 'Content-Type': mime }).send(buffer);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return reply
|
|
43
|
+
.headers({
|
|
44
|
+
'Content-Type': mime,
|
|
45
|
+
'Content-Disposition': `attachment; filename=${filename || path.basename(filepath)}`,
|
|
46
|
+
})
|
|
47
|
+
.send(buffer);
|
|
48
|
+
}
|
|
@@ -0,0 +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 };
|
|
16
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
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
|
+
if (!rows.length && false) {
|
|
39
|
+
return { data: [], relpath, msg: 'empty rows' };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const isDirectory = (await stat(dirpath)).isDirectory();
|
|
43
|
+
|
|
44
|
+
const items = isDirectory ? await readdir(dirpath, { withFileTypes: true }) : [];
|
|
45
|
+
|
|
46
|
+
rows.forEach(row => Object.assign(row, {
|
|
47
|
+
url: `${req.routeOptions.url}/${row.id}/file`,
|
|
48
|
+
filepath: row.url,
|
|
49
|
+
metadata: `${req.routeOptions.url}/${row.id}`,
|
|
50
|
+
exists: !!items.find(el => el.isFile() && el.name === path.basename(row.url))
|
|
51
|
+
}));
|
|
52
|
+
|
|
53
|
+
const result = { relpath, data: rows };
|
|
54
|
+
|
|
55
|
+
if (config.debug) {
|
|
56
|
+
Object.assign(result, { rootDir });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
@@ -0,0 +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
|
+
}
|
|
@@ -0,0 +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
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +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
|
+
});
|
|
66
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
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
|
+
const schemaObj = {
|
|
13
|
+
type: 'object',
|
|
14
|
+
properties: {
|
|
15
|
+
params: {
|
|
16
|
+
type: 'string',
|
|
17
|
+
enum: ['preview', 'download'],
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const params = { config: { policy: ['site', 'user'] } };
|
|
23
|
+
|
|
24
|
+
export default async function route(app) {
|
|
25
|
+
app.post('/site-permissions/:id', params, setPermissions);
|
|
26
|
+
app.get('/site-permissions/:id?', params, getPermissions);
|
|
27
|
+
|
|
28
|
+
app.post('/site-media/upload', params, uploadMedia);
|
|
29
|
+
app.get('/site-media', params, listMedia);
|
|
30
|
+
app.get('/site-media/:id/file', { ...params, schema: schemaObj }, download);
|
|
31
|
+
app.get('/site-media/:id', params, metadata);
|
|
32
|
+
app.delete('/site-media/:id', params, del);
|
|
33
|
+
app.get('/site-media/:id/delete', params, del); // debug
|
|
34
|
+
}
|