@opengis/cms 0.0.32 → 0.0.34
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/index.js +6933 -6487
- package/dist/index.umd.cjs +51 -50
- package/package.json +7 -5
- package/server/plugins/vite.js +18 -30
- package/server/routes/cms/controllers/deleteContent.js +6 -7
- package/server/routes/cms/controllers/deleteMedia.js +76 -76
- package/server/routes/cms/controllers/downloadMedia.js +49 -49
- package/server/routes/cms/controllers/getPermissions.js +15 -15
- package/server/routes/cms/controllers/insertContent.js +7 -7
- package/server/routes/cms/controllers/listMedia.js +94 -94
- package/server/routes/cms/controllers/metadataMedia.js +39 -39
- package/server/routes/cms/controllers/setPermissions.js +49 -49
- package/server/routes/cms/controllers/updateContent.js +16 -14
- package/server/routes/cms/controllers/uploadMedia.js +79 -79
- package/server/routes/cms/utils/getSingle.js +2 -0
- package/server/templates/select/core.user_mentioned.sql +1 -1
|
@@ -1,95 +1,95 @@
|
|
|
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, getMimeType } from '@opengis/fastify-table/utils.js';
|
|
6
|
-
import { createHash } from 'node:crypto';
|
|
7
|
-
|
|
8
|
-
// path.resolve() converts POSIX paths from getFolder to valid Windows paths (Bun/Node fs require this on Windows)
|
|
9
|
-
const rootDir = path.resolve(getFolder(config, 'local'));
|
|
10
|
-
const dir = '/files';
|
|
11
|
-
|
|
12
|
-
mkdirSync(path.join(rootDir, dir), { recursive: true });
|
|
13
|
-
|
|
14
|
-
export default async function listMedia(req, reply) {
|
|
15
|
-
const { pg = pgClients.client, query = {} } = req;
|
|
16
|
-
const { subdir: subdir1 = '', search } = query;
|
|
17
|
-
|
|
18
|
-
if (!pg.pk?.['site.media']) {
|
|
19
|
-
return reply.status(404).send('table not found');
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (typeof subdir1 !== 'string' || subdir1.includes('..')) {
|
|
23
|
-
return reply.status(403).send('invalid params: subdir');
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const subdir = subdir1.replace(/\/{2,}/g, '/');
|
|
27
|
-
const relpath = path.join(dir, subdir1).replace(/\\/g, '/');
|
|
28
|
-
const dirpath = path.join(rootDir, relpath).replace(/\\/g, '/');
|
|
29
|
-
|
|
30
|
-
if (!existsSync(dirpath)) {
|
|
31
|
-
return { data: [], relpath, msg: 'directory not exists' };
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const isDirectory = (await stat(dirpath)).isDirectory();
|
|
35
|
-
|
|
36
|
-
const allItems = isDirectory ? await readdir(dirpath, { withFileTypes: true, recursive: true }) : [];
|
|
37
|
-
const items = isDirectory ? await readdir(dirpath, { withFileTypes: true }) : [];
|
|
38
|
-
|
|
39
|
-
const rows = await pg.query(
|
|
40
|
-
`select
|
|
41
|
-
media_id as id, filename, filetype, filesize, url, description, alt,
|
|
42
|
-
mime, preview_url, created_at, updated_at, created_by, updated_by
|
|
43
|
-
from site.media
|
|
44
|
-
where ${subdir ? 'subdir = $1' : (search ? '1=1' : 'subdir is null')} ${search ? `and filename ilike '%${search.replace(/'/g, "''")}%'` : ''}`,
|
|
45
|
-
[subdir].filter(Boolean),
|
|
46
|
-
).then(el => el.rows || []); // ?.filter(row => items.map(el => el.name).includes(row.filename))
|
|
47
|
-
|
|
48
|
-
const subdirs = items
|
|
49
|
-
.filter(el => el.isDirectory())
|
|
50
|
-
.map(el => ({ type: 'dir', name: el.name }))
|
|
51
|
-
.filter(el => search ? el.name.includes(search) : true);
|
|
52
|
-
|
|
53
|
-
if (subdirs.length) {
|
|
54
|
-
await Promise.all(subdirs.map(async (item) => {
|
|
55
|
-
const items = isDirectory ? await readdir(path.join(dirpath, item.name)) : [];
|
|
56
|
-
Object.assign(item, { count: items.length });
|
|
57
|
-
}));
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const result = { relpath };
|
|
61
|
-
|
|
62
|
-
if (config.debug) {
|
|
63
|
-
Object.assign(result, { rootDir });
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const files = (search ? allItems.filter(el => el.name.includes(search)) : items)
|
|
67
|
-
.filter(el => el.isFile())
|
|
68
|
-
.map(el => {
|
|
69
|
-
const media = rows.find(row => row.filename === el.name);
|
|
70
|
-
const filepath = media ? media.url : ('/files/' + (el.path.split('/files/')[1] ? el.path.split('/files/')[1] + '/' : '') + el.name);
|
|
71
|
-
return media ? {
|
|
72
|
-
type: 'file',
|
|
73
|
-
...media,
|
|
74
|
-
url: `${req.routeOptions.url}/${media.id}/file`,
|
|
75
|
-
preview: `${req.routeOptions.url}/${media.id}/preview`,
|
|
76
|
-
filepath,
|
|
77
|
-
metadata: `${req.routeOptions.url}/${media.id}`,
|
|
78
|
-
} : {
|
|
79
|
-
id: createHash('md5').update(filepath).digest('hex'),
|
|
80
|
-
hash: true,
|
|
81
|
-
type: 'file',
|
|
82
|
-
filename: el.name,
|
|
83
|
-
filepath,
|
|
84
|
-
filetype: getMimeType(el.name)?.startsWith('image/') ? "image" : "other",
|
|
85
|
-
filesize: 0,
|
|
86
|
-
url: filepath,
|
|
87
|
-
mime: getMimeType(el.name),
|
|
88
|
-
preview: filepath,
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
Object.assign(result, { data: subdirs.concat(files) });
|
|
93
|
-
return result;
|
|
94
|
-
|
|
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, getMimeType } from '@opengis/fastify-table/utils.js';
|
|
6
|
+
import { createHash } from 'node:crypto';
|
|
7
|
+
|
|
8
|
+
// path.resolve() converts POSIX paths from getFolder to valid Windows paths (Bun/Node fs require this on Windows)
|
|
9
|
+
const rootDir = path.resolve(getFolder(config, 'local'));
|
|
10
|
+
const dir = '/files';
|
|
11
|
+
|
|
12
|
+
mkdirSync(path.join(rootDir, dir), { recursive: true });
|
|
13
|
+
|
|
14
|
+
export default async function listMedia(req, reply) {
|
|
15
|
+
const { pg = pgClients.client, query = {} } = req;
|
|
16
|
+
const { subdir: subdir1 = '', search } = query;
|
|
17
|
+
|
|
18
|
+
if (!pg.pk?.['site.media']) {
|
|
19
|
+
return reply.status(404).send('table not found');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (typeof subdir1 !== 'string' || subdir1.includes('..')) {
|
|
23
|
+
return reply.status(403).send('invalid params: subdir');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const subdir = subdir1.replace(/\/{2,}/g, '/');
|
|
27
|
+
const relpath = path.join(dir, subdir1).replace(/\\/g, '/');
|
|
28
|
+
const dirpath = path.join(rootDir, relpath).replace(/\\/g, '/');
|
|
29
|
+
|
|
30
|
+
if (!existsSync(dirpath)) {
|
|
31
|
+
return { data: [], relpath, msg: 'directory not exists' };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const isDirectory = (await stat(dirpath)).isDirectory();
|
|
35
|
+
|
|
36
|
+
const allItems = isDirectory ? await readdir(dirpath, { withFileTypes: true, recursive: true }) : [];
|
|
37
|
+
const items = isDirectory ? await readdir(dirpath, { withFileTypes: true }) : [];
|
|
38
|
+
|
|
39
|
+
const rows = await pg.query(
|
|
40
|
+
`select
|
|
41
|
+
media_id as id, filename, filetype, filesize, url, description, alt,
|
|
42
|
+
mime, preview_url, created_at, updated_at, created_by, updated_by
|
|
43
|
+
from site.media
|
|
44
|
+
where ${subdir ? 'subdir = $1' : (search ? '1=1' : 'subdir is null')} ${search ? `and filename ilike '%${search.replace(/'/g, "''")}%'` : ''}`,
|
|
45
|
+
[subdir].filter(Boolean),
|
|
46
|
+
).then(el => el.rows || []); // ?.filter(row => items.map(el => el.name).includes(row.filename))
|
|
47
|
+
|
|
48
|
+
const subdirs = items
|
|
49
|
+
.filter(el => el.isDirectory())
|
|
50
|
+
.map(el => ({ type: 'dir', name: el.name }))
|
|
51
|
+
.filter(el => search ? el.name.includes(search) : true);
|
|
52
|
+
|
|
53
|
+
if (subdirs.length) {
|
|
54
|
+
await Promise.all(subdirs.map(async (item) => {
|
|
55
|
+
const items = isDirectory ? await readdir(path.join(dirpath, item.name)) : [];
|
|
56
|
+
Object.assign(item, { count: items.length });
|
|
57
|
+
}));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const result = { relpath };
|
|
61
|
+
|
|
62
|
+
if (config.debug) {
|
|
63
|
+
Object.assign(result, { rootDir });
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const files = (search ? allItems.filter(el => el.name.includes(search)) : items)
|
|
67
|
+
.filter(el => el.isFile())
|
|
68
|
+
.map(el => {
|
|
69
|
+
const media = rows.find(row => row.filename === el.name);
|
|
70
|
+
const filepath = media ? media.url : ('/files/' + (el.path.split('/files/')[1] ? el.path.split('/files/')[1] + '/' : '') + el.name);
|
|
71
|
+
return media ? {
|
|
72
|
+
type: 'file',
|
|
73
|
+
...media,
|
|
74
|
+
url: `${req.routeOptions.url}/${media.id}/file`,
|
|
75
|
+
preview: `${req.routeOptions.url}/${media.id}/preview`,
|
|
76
|
+
filepath,
|
|
77
|
+
metadata: `${req.routeOptions.url}/${media.id}`,
|
|
78
|
+
} : {
|
|
79
|
+
id: createHash('md5').update(filepath).digest('hex'),
|
|
80
|
+
hash: true,
|
|
81
|
+
type: 'file',
|
|
82
|
+
filename: el.name,
|
|
83
|
+
filepath,
|
|
84
|
+
filetype: getMimeType(el.name)?.startsWith('image/') ? "image" : "other",
|
|
85
|
+
filesize: 0,
|
|
86
|
+
url: filepath,
|
|
87
|
+
mime: getMimeType(el.name),
|
|
88
|
+
preview: filepath,
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
Object.assign(result, { data: subdirs.concat(files) });
|
|
93
|
+
return result;
|
|
94
|
+
|
|
95
95
|
}
|
|
@@ -1,39 +1,39 @@
|
|
|
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
|
-
// path.resolve() converts POSIX paths from getFolder to valid Windows paths (Bun/Node fs require this on Windows)
|
|
7
|
-
const rootDir = path.resolve(getFolder(config, 'local'));
|
|
8
|
-
|
|
9
|
-
export default async function metadataMedia({
|
|
10
|
-
routeOptions = {}, pg = pgClients.client, params = {},
|
|
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 data = await pg.query(
|
|
21
|
-
'select * from site.media where media_id = $1 and url is not null',
|
|
22
|
-
[params.id],
|
|
23
|
-
).then(el => el.rows?.[0]);
|
|
24
|
-
|
|
25
|
-
if (!data) {
|
|
26
|
-
return reply.status(404).send('media not found: ' + params.id);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const filepath = path.join(rootDir, data.url);
|
|
30
|
-
|
|
31
|
-
Object.assign(data, {
|
|
32
|
-
url: `${routeOptions.url.replace(':id', params.id)}/file`,
|
|
33
|
-
preview: `${routeOptions.url.replace(':id', params.id)}/preview`,
|
|
34
|
-
filepath: data.url,
|
|
35
|
-
exists: existsSync(filepath),
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
return reply.status(200).send(data);
|
|
39
|
-
}
|
|
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
|
+
// path.resolve() converts POSIX paths from getFolder to valid Windows paths (Bun/Node fs require this on Windows)
|
|
7
|
+
const rootDir = path.resolve(getFolder(config, 'local'));
|
|
8
|
+
|
|
9
|
+
export default async function metadataMedia({
|
|
10
|
+
routeOptions = {}, pg = pgClients.client, params = {},
|
|
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 data = await pg.query(
|
|
21
|
+
'select * from site.media where media_id = $1 and url is not null',
|
|
22
|
+
[params.id],
|
|
23
|
+
).then(el => el.rows?.[0]);
|
|
24
|
+
|
|
25
|
+
if (!data) {
|
|
26
|
+
return reply.status(404).send('media not found: ' + params.id);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const filepath = path.join(rootDir, data.url);
|
|
30
|
+
|
|
31
|
+
Object.assign(data, {
|
|
32
|
+
url: `${routeOptions.url.replace(':id', params.id)}/file`,
|
|
33
|
+
preview: `${routeOptions.url.replace(':id', params.id)}/preview`,
|
|
34
|
+
filepath: data.url,
|
|
35
|
+
exists: existsSync(filepath),
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
return reply.status(200).send(data);
|
|
39
|
+
}
|
|
@@ -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
|
}
|
|
@@ -47,20 +47,19 @@ export default async function updateContent(req, reply) {
|
|
|
47
47
|
return reply.status(400).send('empty body');
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
// order priority - custom columns -> default for pages
|
|
51
|
+
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] || {});
|
|
52
|
+
|
|
50
53
|
const arr = config.pg ? await pg.query(`select array_agg(relname)::text[] from pg_class a
|
|
51
|
-
|
|
52
|
-
|
|
54
|
+
left join pg_namespace b on a.relnamespace=b.oid
|
|
55
|
+
where a.relam=2 and b.nspname='data'`).then(el => el.rows?.[0]?.array_agg || []) : [];
|
|
53
56
|
|
|
54
|
-
if (!arr.length) {
|
|
57
|
+
if (!arr.length && type !== 'pages') {
|
|
55
58
|
return reply.status(400).send('empty schema: data');
|
|
56
59
|
}
|
|
57
60
|
|
|
58
61
|
const table = arr.find(el => el === params.type);
|
|
59
62
|
|
|
60
|
-
// order priority - custom columns -> default for pages
|
|
61
|
-
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] || {});
|
|
62
|
-
|
|
63
|
-
|
|
64
63
|
const loadTable = type === 'pages' ? await getTemplate('table', 'single.default.table') : {};
|
|
65
64
|
const columns = type === 'pages'
|
|
66
65
|
? (loadTable?.columns || []).concat(contentColumns.filter(col => loadTable?.columns.findIndex(el => el.name === col.name) === -1))
|
|
@@ -96,13 +95,14 @@ export default async function updateContent(req, reply) {
|
|
|
96
95
|
return reply.status(404).send('contents not found');
|
|
97
96
|
}
|
|
98
97
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
98
|
+
// ? deprecated, blocks if only default columns provided, therefore commented for now
|
|
99
|
+
// const contentId = cid === 'pages'
|
|
100
|
+
// ? await pg.query('select content_id from site.content_data where object_id=$1', [id]).then(el => el.rows?.[0]?.content_id)
|
|
101
|
+
// : cid;
|
|
102
102
|
|
|
103
|
-
if (!contentId) {
|
|
104
|
-
|
|
105
|
-
}
|
|
103
|
+
// if (!contentId) {
|
|
104
|
+
// return reply.status(404).send('contents not found: 2');
|
|
105
|
+
// }
|
|
106
106
|
|
|
107
107
|
const columnList = columns?.map?.(el => el.name) || [];
|
|
108
108
|
const types = columns?.reduce?.((acc, curr) => ({ ...acc, [curr.name]: curr.type || 'text' }), {}) || {};
|
|
@@ -133,7 +133,9 @@ export default async function updateContent(req, reply) {
|
|
|
133
133
|
data: { ...body, content_type_id: ctid1 },
|
|
134
134
|
uid: user?.uid,
|
|
135
135
|
});
|
|
136
|
-
|
|
136
|
+
// if (contentId) {
|
|
137
|
+
// await client.query(`delete from site.content_data where content_id=$1`, [contentId]);
|
|
138
|
+
// }
|
|
137
139
|
const objectId = (ctname === 'pages' || ['single', 'pages'].includes(type)) && id ? id : cid;
|
|
138
140
|
await client.query(`delete from site.content_data where object_id=$1`, [objectId]);
|
|
139
141
|
await Promise.all(keys.map(async key => dataInsert({
|
|
@@ -1,80 +1,80 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import { mkdir } from 'node:fs/promises';
|
|
3
|
-
|
|
4
|
-
import { uploadMultiPart, config, getFolder, dataInsert, pgClients } from "@opengis/fastify-table/utils.js";
|
|
5
|
-
|
|
6
|
-
// path.resolve() converts POSIX paths from getFolder to valid Windows paths (Bun/Node fs require this on Windows)
|
|
7
|
-
const rootDir = path.resolve(getFolder(config, 'local'));
|
|
8
|
-
const dir = '/files';
|
|
9
|
-
|
|
10
|
-
export default async function uploadMedia(req, reply) {
|
|
11
|
-
const { pg = pgClients.client, user = {}, query = {} } = req;
|
|
12
|
-
|
|
13
|
-
if (!pg?.pk?.['site.media']) {
|
|
14
|
-
return reply.status(404).send('table not found');
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
if (query.subdir && (typeof query.subdir !== 'string' || query.subdir.includes('..'))) {
|
|
18
|
-
return reply.status(403).send('invalid query params: subdir');
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// upload assets
|
|
22
|
-
if (req.headers['content-type']?.split?.(';')?.shift?.() === 'multipart/form-data') {
|
|
23
|
-
const file = await uploadMultiPart(req, { subdir: query.subdir || '', originalFilename: true }).catch(err => {
|
|
24
|
-
if (err.message === 'file with specified name already exists in directory') {
|
|
25
|
-
err.message = 'Файл з вказаною назвою вже існує';
|
|
26
|
-
err.statusCode = 400;
|
|
27
|
-
}
|
|
28
|
-
throw err;
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
const { originalFilename: filename, filetype, mimetype } = file;
|
|
32
|
-
const relpath = path.join(dir, query.subdir || '', file.originalFilename).replace(/\\/g, '/');
|
|
33
|
-
|
|
34
|
-
const id = await dataInsert({
|
|
35
|
-
pg,
|
|
36
|
-
table: 'site.media',
|
|
37
|
-
data: {
|
|
38
|
-
filename,
|
|
39
|
-
filetype,
|
|
40
|
-
subdir: query.subdir,
|
|
41
|
-
url: relpath,
|
|
42
|
-
mime: mimetype,
|
|
43
|
-
filesize: file.size,
|
|
44
|
-
},
|
|
45
|
-
uid: user?.uid,
|
|
46
|
-
}).then(el => el?.rows?.[0]?.media_id);
|
|
47
|
-
|
|
48
|
-
return reply.status(200).send({
|
|
49
|
-
res: 'ok',
|
|
50
|
-
name: filename,
|
|
51
|
-
type: 'file',
|
|
52
|
-
mimetype,
|
|
53
|
-
result: {
|
|
54
|
-
file_id: id,
|
|
55
|
-
format: file.extension,
|
|
56
|
-
size: file.size,
|
|
57
|
-
// entity_id: resultInsert?.entity_id,
|
|
58
|
-
file_path: relpath,
|
|
59
|
-
file_name: filename,
|
|
60
|
-
dir: path.dirname(relpath).replace(/\\/g, '/'),
|
|
61
|
-
native_file_name: filename,
|
|
62
|
-
},
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (!query.subdir) {
|
|
67
|
-
return reply.status(400).send('not enough query params: subdir');
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// create directory
|
|
71
|
-
const relpath = path.join(dir, query.subdir).replace(/\\/g, '/');
|
|
72
|
-
const dirpath = path.join(rootDir, relpath);
|
|
73
|
-
await mkdir(dirpath, { recursive: true });
|
|
74
|
-
|
|
75
|
-
return reply.status(200).send({
|
|
76
|
-
relpath,
|
|
77
|
-
dirname: path.basename(query.subdir),
|
|
78
|
-
type: 'dir',
|
|
79
|
-
});
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { mkdir } from 'node:fs/promises';
|
|
3
|
+
|
|
4
|
+
import { uploadMultiPart, config, getFolder, dataInsert, pgClients } from "@opengis/fastify-table/utils.js";
|
|
5
|
+
|
|
6
|
+
// path.resolve() converts POSIX paths from getFolder to valid Windows paths (Bun/Node fs require this on Windows)
|
|
7
|
+
const rootDir = path.resolve(getFolder(config, 'local'));
|
|
8
|
+
const dir = '/files';
|
|
9
|
+
|
|
10
|
+
export default async function uploadMedia(req, reply) {
|
|
11
|
+
const { pg = pgClients.client, user = {}, query = {} } = req;
|
|
12
|
+
|
|
13
|
+
if (!pg?.pk?.['site.media']) {
|
|
14
|
+
return reply.status(404).send('table not found');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (query.subdir && (typeof query.subdir !== 'string' || query.subdir.includes('..'))) {
|
|
18
|
+
return reply.status(403).send('invalid query params: subdir');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// upload assets
|
|
22
|
+
if (req.headers['content-type']?.split?.(';')?.shift?.() === 'multipart/form-data') {
|
|
23
|
+
const file = await uploadMultiPart(req, { subdir: query.subdir || '', originalFilename: true }).catch(err => {
|
|
24
|
+
if (err.message === 'file with specified name already exists in directory') {
|
|
25
|
+
err.message = 'Файл з вказаною назвою вже існує';
|
|
26
|
+
err.statusCode = 400;
|
|
27
|
+
}
|
|
28
|
+
throw err;
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const { originalFilename: filename, filetype, mimetype } = file;
|
|
32
|
+
const relpath = path.join(dir, query.subdir || '', file.originalFilename).replace(/\\/g, '/');
|
|
33
|
+
|
|
34
|
+
const id = await dataInsert({
|
|
35
|
+
pg,
|
|
36
|
+
table: 'site.media',
|
|
37
|
+
data: {
|
|
38
|
+
filename,
|
|
39
|
+
filetype,
|
|
40
|
+
subdir: query.subdir,
|
|
41
|
+
url: relpath,
|
|
42
|
+
mime: mimetype,
|
|
43
|
+
filesize: file.size,
|
|
44
|
+
},
|
|
45
|
+
uid: user?.uid,
|
|
46
|
+
}).then(el => el?.rows?.[0]?.media_id);
|
|
47
|
+
|
|
48
|
+
return reply.status(200).send({
|
|
49
|
+
res: 'ok',
|
|
50
|
+
name: filename,
|
|
51
|
+
type: 'file',
|
|
52
|
+
mimetype,
|
|
53
|
+
result: {
|
|
54
|
+
file_id: id,
|
|
55
|
+
format: file.extension,
|
|
56
|
+
size: file.size,
|
|
57
|
+
// entity_id: resultInsert?.entity_id,
|
|
58
|
+
file_path: relpath,
|
|
59
|
+
file_name: filename,
|
|
60
|
+
dir: path.dirname(relpath).replace(/\\/g, '/'),
|
|
61
|
+
native_file_name: filename,
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!query.subdir) {
|
|
67
|
+
return reply.status(400).send('not enough query params: subdir');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// create directory
|
|
71
|
+
const relpath = path.join(dir, query.subdir).replace(/\\/g, '/');
|
|
72
|
+
const dirpath = path.join(rootDir, relpath);
|
|
73
|
+
await mkdir(dirpath, { recursive: true });
|
|
74
|
+
|
|
75
|
+
return reply.status(200).send({
|
|
76
|
+
relpath,
|
|
77
|
+
dirname: path.basename(query.subdir),
|
|
78
|
+
type: 'dir',
|
|
79
|
+
});
|
|
80
80
|
}
|
|
@@ -101,6 +101,7 @@ export default async function getSingle({
|
|
|
101
101
|
and ${localeQuery || '1=1'}
|
|
102
102
|
and ${contentQuery || 'true'}
|
|
103
103
|
and ${id ? `$2 in (slug, content_id)` : 'true'}
|
|
104
|
+
and content_id<>'pages'
|
|
104
105
|
order by case when status='archived' then true else false end, published_at desc nulls last
|
|
105
106
|
LIMIT ${limit} OFFSET ${id ? 0 : offset}
|
|
106
107
|
`;
|
|
@@ -120,6 +121,7 @@ export default async function getSingle({
|
|
|
120
121
|
and $1=$1 and $2=$2 and ${contentQuery || 'true'}
|
|
121
122
|
)
|
|
122
123
|
and ${statusQuery || 'true'}
|
|
124
|
+
and content_id<>'pages'
|
|
123
125
|
`, [contentId, id]).then(el => el.rows?.[0] || {});
|
|
124
126
|
|
|
125
127
|
const { rows = [] } = await pg.query(q, [contentId, id || '']);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
select uid, coalesce(sur_name,'')||coalesce(' '||user_name,'') as text, email from admin.users
|
|
1
|
+
select uid, coalesce(sur_name,'')||coalesce(' '||user_name,'') as text, email from admin.users
|
|
2
2
|
where enabled order by coalesce(sur_name,'')||coalesce(' '||user_name,'')
|