@opengis/cms 0.0.10 → 0.0.12
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/cms.js +3615 -2931
- package/dist/cms.umd.cjs +13 -13
- package/dist/style.css +1 -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/server/migrations/media.sql +0 -30
|
@@ -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
|
+
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
create schema if not exists crm;
|
|
2
|
-
create table if not exists crm.media();
|
|
3
|
-
|
|
4
|
-
CREATE TABLE IF NOT EXISTS crm.media();
|
|
5
|
-
ALTER TABLE crm.media DROP CONSTRAINT IF EXISTS crm_media_id_pkey;
|
|
6
|
-
ALTER TABLE crm.media ADD COLUMN IF NOT EXISTS media_id text NOT NULL DEFAULT next_id();
|
|
7
|
-
|
|
8
|
-
ALTER TABLE crm.media ADD COLUMN IF NOT EXISTS uploaded_name text;
|
|
9
|
-
ALTER TABLE crm.media ADD COLUMN IF NOT EXISTS file_path text;
|
|
10
|
-
ALTER TABLE crm.media ADD COLUMN IF NOT EXISTS caption text;
|
|
11
|
-
ALTER TABLE crm.media ADD COLUMN IF NOT EXISTS altname text;
|
|
12
|
-
ALTER TABLE crm.media ADD COLUMN IF NOT EXISTS size numeric;
|
|
13
|
-
ALTER TABLE crm.media ADD COLUMN IF NOT EXISTS ext text;
|
|
14
|
-
ALTER TABLE crm.media ADD COLUMN IF NOT EXISTS tags text[];
|
|
15
|
-
ALTER TABLE crm.media ADD COLUMN IF NOT EXISTS uid text;
|
|
16
|
-
ALTER TABLE crm.media ADD COLUMN IF NOT EXISTS files json;
|
|
17
|
-
ALTER TABLE crm.media ADD COLUMN IF NOT EXISTS cdate timestamp without time zone DEFAULT (now())::timestamp without time zone;
|
|
18
|
-
ALTER TABLE crm.media ADD COLUMN IF NOT EXISTS editor_id text;
|
|
19
|
-
ALTER TABLE crm.media ADD COLUMN IF NOT EXISTS editor_date timestamp without time zone;
|
|
20
|
-
ALTER TABLE crm.media ADD CONSTRAINT crm_media_id_pkey PRIMARY KEY (media_id);
|
|
21
|
-
|
|
22
|
-
comment on table crm.media is 'Медіа файли';
|
|
23
|
-
|
|
24
|
-
comment on column crm.media.uploaded_name is 'Назва файлу';
|
|
25
|
-
comment on column crm.media.file_path is 'Відносний шлях до файлу';
|
|
26
|
-
comment on column crm.media.caption is 'Заголовок';
|
|
27
|
-
comment on column crm.media.altname is 'Альтернативна назва';
|
|
28
|
-
comment on column crm.media.size is 'Розмір файлу';
|
|
29
|
-
comment on column crm.media.ext is 'Розширення файлу';
|
|
30
|
-
comment on column crm.media.tags is 'Теги файлу';
|