@opengis/cms 0.0.7 → 0.0.8
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 +1505 -1494
- package/dist/cms.umd.cjs +11 -11
- package/package.json +6 -4
- package/server/app.js +25 -0
- package/server/config.js +5 -0
- package/server/index.js +23 -0
- package/server/migrations/media.sql +30 -0
- package/server/plugins/hook.js +91 -0
- package/server/plugins/vite.js +80 -0
- package/server/routes/builder/controllers/cms.builder.delete.js +21 -0
- package/server/routes/builder/controllers/cms.builder.get.js +17 -0
- package/server/routes/builder/controllers/cms.builder.list.js +16 -0
- package/server/routes/builder/controllers/cms.builder.post.js +21 -0
- package/server/routes/builder/controllers/cms.builder.put.js +23 -0
- package/server/routes/builder/index.mjs +22 -0
- package/server/routes/category/controllers/cms.category.delete.js +21 -0
- package/server/routes/category/controllers/cms.category.get.js +17 -0
- package/server/routes/category/controllers/cms.category.list.js +16 -0
- package/server/routes/category/controllers/cms.category.post.js +21 -0
- package/server/routes/category/controllers/cms.category.put.js +23 -0
- package/server/routes/category/index.mjs +22 -0
- package/server/routes/manager/controllers/cms.manager.delete.js +22 -0
- package/server/routes/manager/controllers/cms.manager.get.js +21 -0
- package/server/routes/manager/controllers/cms.manager.list.js +31 -0
- package/server/routes/manager/controllers/cms.manager.post.js +28 -0
- package/server/routes/manager/controllers/cms.manager.put.js +23 -0
- package/server/routes/manager/index.mjs +22 -0
- package/server/routes/media/controllers/delete.js +59 -0
- package/server/routes/media/controllers/edit.js +94 -0
- package/server/routes/media/controllers/list.js +74 -0
- package/server/routes/media/controllers/metadata.js +51 -0
- package/server/routes/media/controllers/preview.js +47 -0
- package/server/routes/media/controllers/upload.js +79 -0
- package/server/routes/media/index.mjs +16 -0
- package/server/routes/root.mjs +15 -0
- package/server/templates/cls/cms.category_type.json +10 -0
- package/server/templates/cls/cms.content_review_status.json +10 -0
- package/server/templates/cls/cms.content_status.json +10 -0
- package/server/templates/cls/cms.content_type.json +10 -0
- package/server/templates/cls/cms.lang.json +10 -0
- package/server/templates/page/login.html +59 -0
- package/server/templates/select/cms.category_id.sql +1 -0
- package/server/templates/select/cms.type_id.sql +1 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import cmsManagerGet from './controllers/cms.manager.get.js';
|
|
2
|
+
import cmsManagerList from './controllers/cms.manager.list.js';
|
|
3
|
+
import cmsManagerPut from './controllers/cms.manager.put.js';
|
|
4
|
+
import cmsManagerPost from './controllers/cms.manager.post.js';
|
|
5
|
+
import cmsManagerDelete from './controllers/cms.manager.delete.js';
|
|
6
|
+
|
|
7
|
+
export default async function route(app) {
|
|
8
|
+
// manager add
|
|
9
|
+
app.post('/cms-manager/:template', { config: { policy: ['site'] }}, cmsManagerPost);
|
|
10
|
+
|
|
11
|
+
// manager edit
|
|
12
|
+
app.put('/cms-manager/:id', { config: { policy: ['site'] }}, cmsManagerPut);
|
|
13
|
+
|
|
14
|
+
// manager list
|
|
15
|
+
app.get('/cms-manager/:template', { config: { policy: ['site'] }}, cmsManagerList);
|
|
16
|
+
|
|
17
|
+
// manager get
|
|
18
|
+
app.get('/cms-manager/:template/:id', { config: { policy: ['site'] }}, cmsManagerGet);
|
|
19
|
+
|
|
20
|
+
// manager delete
|
|
21
|
+
app.delete('/cms-manager/:id', { config: { policy: ['site'] }}, cmsManagerDelete);
|
|
22
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { rm } from 'node:fs/promises';
|
|
4
|
+
|
|
5
|
+
import { config, getToken, dataDelete, getFolder, pgClients } from "@opengis/fastify-table/utils.js";
|
|
6
|
+
|
|
7
|
+
const rootDir = getFolder(config, 'local');
|
|
8
|
+
|
|
9
|
+
export default async function deleteMedia({
|
|
10
|
+
pg = pgClients.client, params = {}, user = {},
|
|
11
|
+
}, reply) {
|
|
12
|
+
|
|
13
|
+
if (!params?.token) {
|
|
14
|
+
return reply.status(400).send('not enough params: token');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const tokenData = await getToken({
|
|
18
|
+
uid: user?.uid || 0,
|
|
19
|
+
token: params.token,
|
|
20
|
+
json: 1,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const { dir, name, relpath, id } = pg.pk?.['crm.media'] && tokenData?.type !== 'dir'
|
|
24
|
+
? await pg.query(`select media_id as id, uploaded_name as name, file_path as "relpath" from crm.media where $1 in (media_id, file_path)`, [tokenData?.id || tokenData?.relpath || params.token])
|
|
25
|
+
.then(el => el.rows?.[0] || {})
|
|
26
|
+
: tokenData;
|
|
27
|
+
|
|
28
|
+
if (!dir && !(id && relpath)) {
|
|
29
|
+
return reply.status(403).send('access restricted: root dir');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// delete file
|
|
33
|
+
if (id && relpath) {
|
|
34
|
+
const res = await dataDelete({
|
|
35
|
+
id,
|
|
36
|
+
table: 'crm.media',
|
|
37
|
+
uid: user?.uid || 0,
|
|
38
|
+
});
|
|
39
|
+
const filepath = path.join(rootDir, relpath);
|
|
40
|
+
|
|
41
|
+
if (existsSync(filepath)) {
|
|
42
|
+
await rm(filepath, { recursive: true });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
id: tokenData?.id || id,
|
|
47
|
+
name: res?.uploaded_name,
|
|
48
|
+
size: res?.size,
|
|
49
|
+
extension: res?.ext,
|
|
50
|
+
caption: res?.caption,
|
|
51
|
+
altname: res?.altname,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// delete directory
|
|
56
|
+
const dirpath = path.join(rootDir, relpath);
|
|
57
|
+
await rm(dirpath, { recursive: true });
|
|
58
|
+
return reply.status(200).send({ name: path.basename(relpath) });
|
|
59
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { rename, readdir } from 'node:fs/promises';
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
|
+
|
|
5
|
+
import { config, getToken, getFolder, dataUpdate, pgClients } from "@opengis/fastify-table/utils.js";
|
|
6
|
+
|
|
7
|
+
const rootDir = getFolder(config, 'local');
|
|
8
|
+
|
|
9
|
+
export default async function editMedia({
|
|
10
|
+
pg = pgClients.client, params = {}, user = {}, body = {},
|
|
11
|
+
}, reply) {
|
|
12
|
+
|
|
13
|
+
const tokenData = await getToken({
|
|
14
|
+
uid: user?.uid || 0,
|
|
15
|
+
token: params.token,
|
|
16
|
+
json: 1,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const objdata = pg.pk?.['crm.media'] && !tokenData
|
|
20
|
+
? await pg.query(`select media_id as id, uploaded_name as name, file_path as "relpath" from crm.media where media_id=$1`, [params.token]).then(el => el.rows?.[0] || {})
|
|
21
|
+
: tokenData;
|
|
22
|
+
|
|
23
|
+
const { id, name } = objdata;
|
|
24
|
+
const relpath = (objdata?.relpath || tokenData?.relpath)?.replace(/\\/g, '/');
|
|
25
|
+
|
|
26
|
+
if ((tokenData?.type === 'file' && !id) || !relpath) {
|
|
27
|
+
return reply.status(400).send('invalid params: token');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const data = {};
|
|
31
|
+
const oldfilepath = path.join(rootDir, relpath);
|
|
32
|
+
|
|
33
|
+
if (tokenData?.type === 'dir' && !body?.name) {
|
|
34
|
+
return reply.status(400).send('not enough body params: name');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (body?.name) {
|
|
38
|
+
const newfilepath = path.join(rootDir, path.dirname(relpath), body.name);
|
|
39
|
+
|
|
40
|
+
if (!existsSync(oldfilepath)) {
|
|
41
|
+
return reply.status(404).send('file / directory not found');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (existsSync(newfilepath)) {
|
|
45
|
+
return reply.status(400).send('file / directory with such name already exists');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// sync file path in db data
|
|
49
|
+
const arr = tokenData?.type === 'dir' ? await readdir(oldfilepath, { withFileTypes: true }) : [];
|
|
50
|
+
|
|
51
|
+
await rename(oldfilepath, newfilepath);
|
|
52
|
+
|
|
53
|
+
if (tokenData?.type === 'dir') {
|
|
54
|
+
const relpaths = arr.filter(el => el.isFile()).map(el => path.join(tokenData.relpath, el.name).replace(/\\/g, '/'));
|
|
55
|
+
const { rows = [] } = pg.pk?.['crm.media'] ? await pg.query(`select media_id as id, file_path as relpath from crm.media where file_path=any($1::text[])`, [relpaths]) : {};
|
|
56
|
+
await Promise.all(rows.map(async (el) => dataUpdate({
|
|
57
|
+
id: el.id,
|
|
58
|
+
table: 'crm.media',
|
|
59
|
+
data: {
|
|
60
|
+
file_path: el.relpath.replace(relpath.replace(/\\/g, '/'), path.join(path.dirname(relpath), body.name).replace(/\\/g, '/'))
|
|
61
|
+
},
|
|
62
|
+
uid: user?.uid || 0,
|
|
63
|
+
})));
|
|
64
|
+
return reply.status(200).send({
|
|
65
|
+
name: body.name,
|
|
66
|
+
relpath: path.join(path.dirname(relpath), body.name).replace(/\\/g, '/'),
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
Object.assign(data, {
|
|
70
|
+
uploaded_name: body.name,
|
|
71
|
+
file_path: path.join(path.dirname(relpath), body.name).replace(/\\/g, '/'),
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (body?.caption) Object.assign(data, { caption: body.caption });
|
|
76
|
+
if (body?.altname) Object.assign(data, { altname: body.altname });
|
|
77
|
+
|
|
78
|
+
const res = await dataUpdate({
|
|
79
|
+
id,
|
|
80
|
+
table: 'crm.media',
|
|
81
|
+
data,
|
|
82
|
+
uid: user?.uid || 0,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
id: tokenData?.id || id,
|
|
87
|
+
name: res?.uploaded_name,
|
|
88
|
+
relpath: res?.file_path,
|
|
89
|
+
size: res?.size,
|
|
90
|
+
extension: res?.ext,
|
|
91
|
+
caption: res?.caption,
|
|
92
|
+
altname: res?.altname,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
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, setToken } 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 = {}, user = {} } = req;
|
|
12
|
+
const { dir } = query;
|
|
13
|
+
const dirpath = path.join(rootDir, 'media', dir || '');
|
|
14
|
+
|
|
15
|
+
if (dir && (typeof dir !== 'string' || dir.includes('..'))) {
|
|
16
|
+
return reply.status(403).send('invalid params: dir');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (!existsSync(dirpath)) {
|
|
20
|
+
return { data: [], dir };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const token = setToken({
|
|
24
|
+
ids: [JSON.stringify({ dir, name: dir, relpath: path.join('/media', dir || '').replace(/\\/g, '/') })],
|
|
25
|
+
uid: user?.uid || 0,
|
|
26
|
+
array: 1,
|
|
27
|
+
})?.[0];
|
|
28
|
+
|
|
29
|
+
const isDirectory = (await stat(dirpath)).isDirectory();
|
|
30
|
+
|
|
31
|
+
const items = isDirectory ? await readdir(dirpath) : [];
|
|
32
|
+
|
|
33
|
+
const relpaths = items.map(el => path.join('/media', dir || '', el).replace(/\\/g, '/'));
|
|
34
|
+
const { rows = [] } = await pg.query(`select media_id as id, uploaded_name as name, file_path as relpath from crm.media where file_path = any($1::text[])`, [relpaths]);
|
|
35
|
+
const ids = rows.reduce((acc, curr) => Object.assign(acc, { [curr.relpath]: curr.id }), {});
|
|
36
|
+
|
|
37
|
+
const data = await Promise.all(items.map(async (item) => {
|
|
38
|
+
const itempath = path.join(dirpath, item);
|
|
39
|
+
const extension = path.extname(item) === '' ? null : path.extname(item).split('.').pop();
|
|
40
|
+
const { ctime, mtime, size } = await stat(itempath);
|
|
41
|
+
const type = (await stat(itempath)).isDirectory() ? 'dir' : 'file';
|
|
42
|
+
const childList = type === 'dir' ? await readdir(itempath) : [];
|
|
43
|
+
const count = type === 'dir' ? childList.length : undefined;
|
|
44
|
+
return {
|
|
45
|
+
id: ids[path.join('/media', dir || '', item).replace(/\\/g, '/')],
|
|
46
|
+
name: item,
|
|
47
|
+
type,
|
|
48
|
+
count,
|
|
49
|
+
size,
|
|
50
|
+
extension,
|
|
51
|
+
token: setToken({
|
|
52
|
+
ids: [JSON.stringify({
|
|
53
|
+
id: ids[path.join('/media', dir || '', item).replace(/\\/g, '/')],
|
|
54
|
+
dir,
|
|
55
|
+
relpath: path.join('/media', dir || '', item).replace(/\\/g, '/'),
|
|
56
|
+
name: item,
|
|
57
|
+
type,
|
|
58
|
+
})],
|
|
59
|
+
uid: user?.uid || 0,
|
|
60
|
+
array: 1,
|
|
61
|
+
})[0],
|
|
62
|
+
ctime,
|
|
63
|
+
mtime,
|
|
64
|
+
};
|
|
65
|
+
}));
|
|
66
|
+
|
|
67
|
+
const result = { dir, token, data };
|
|
68
|
+
|
|
69
|
+
if (config.debug) {
|
|
70
|
+
Object.assign(result, { rootDir });
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { stat } from 'node:fs/promises';
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
|
+
|
|
5
|
+
import { config, getToken, getFolder, pgClients } from "@opengis/fastify-table/utils.js";
|
|
6
|
+
|
|
7
|
+
const rootDir = getFolder(config, 'local');
|
|
8
|
+
|
|
9
|
+
export default async function metadataMedia({
|
|
10
|
+
pg = pgClients.client, params = {}, user = {},
|
|
11
|
+
}, reply) {
|
|
12
|
+
if (!params.token) {
|
|
13
|
+
return reply.status(400).send('not enough params: token');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const tokenData = await getToken({
|
|
17
|
+
uid: user?.uid || 0,
|
|
18
|
+
token: params.token,
|
|
19
|
+
json: 1,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const { relpath, caption, altname, id } = !tokenData && pg.pk?.['crm.media']
|
|
23
|
+
? await pg.query(`select media_id as id, file_path as "relpath", caption from crm.media where media_id=$1`, [params.token]).then(el => el.rows?.[0] || {})
|
|
24
|
+
: {};
|
|
25
|
+
|
|
26
|
+
if ((!tokenData?.name || tokenData?.type !== 'file') && !relpath) {
|
|
27
|
+
return reply.status(400).send('invalid params: token');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const filepath = tokenData?.name
|
|
31
|
+
? path.join(rootDir, 'media', tokenData.dir || '', tokenData.name)
|
|
32
|
+
: path.join(rootDir, relpath);
|
|
33
|
+
|
|
34
|
+
if (!existsSync(filepath)) {
|
|
35
|
+
return reply.status(404).send('file not found');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const stats = await stat(filepath);
|
|
39
|
+
const { ctime, mtime, size } = stats;
|
|
40
|
+
|
|
41
|
+
return reply.status(200).send({
|
|
42
|
+
id: tokenData?.id || id,
|
|
43
|
+
name: path.basename(filepath),
|
|
44
|
+
size,
|
|
45
|
+
extension: path.extname(filepath)?.split?.('.')?.pop?.(),
|
|
46
|
+
ctime, // creation timestamp
|
|
47
|
+
mtime, // last modification timestamp
|
|
48
|
+
caption,
|
|
49
|
+
altname,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
|
|
5
|
+
import { config, getToken, getFolder } from "@opengis/fastify-table/utils.js";
|
|
6
|
+
import { getMimeType } from '@opengis/fastify-file/utils.js';
|
|
7
|
+
|
|
8
|
+
const rootDir = getFolder(config, 'local');
|
|
9
|
+
|
|
10
|
+
export default async function deleteMedia({
|
|
11
|
+
params = {}, query = {}, user = {},
|
|
12
|
+
}, reply) {
|
|
13
|
+
|
|
14
|
+
if (!params?.token) {
|
|
15
|
+
return reply.status(400).send('not enough params: token');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const tokenData = await getToken({
|
|
19
|
+
uid: user?.uid || 0,
|
|
20
|
+
token: params.token,
|
|
21
|
+
json: 1,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const { relpath } = tokenData || {};
|
|
25
|
+
|
|
26
|
+
if (!relpath) {
|
|
27
|
+
return reply.status(403).send('invalid token');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const filepath = path.join(rootDir, relpath);
|
|
31
|
+
|
|
32
|
+
if (!existsSync(filepath)) {
|
|
33
|
+
return reply.status(404).send('file not found');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const buffer = await readFile(filepath, { buffer: true });
|
|
37
|
+
|
|
38
|
+
if (query?.download) {
|
|
39
|
+
const headers = {
|
|
40
|
+
'Content-Type': getMimeType(filepath),
|
|
41
|
+
'Content-Disposition': `attachment; filename=${path.basename(filepath)}`
|
|
42
|
+
};
|
|
43
|
+
return reply.headers(headers).send(buffer);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return reply.headers({ 'Content-Type': getMimeType(filepath) }).send(buffer);
|
|
47
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { mkdir, rename } from 'node:fs/promises';
|
|
3
|
+
|
|
4
|
+
import { config, getToken, getFolder, setToken, dataInsert } from "@opengis/fastify-table/utils.js";
|
|
5
|
+
import { uploadMultiPart } from '@opengis/fastify-file/utils.js';
|
|
6
|
+
|
|
7
|
+
const rootDir = getFolder(config, 'local');
|
|
8
|
+
|
|
9
|
+
export default async function uploadMedia(req, reply) {
|
|
10
|
+
const { params = {}, user = {}, body = {} } = req;
|
|
11
|
+
|
|
12
|
+
if (!params.token) {
|
|
13
|
+
return reply.status(400).send('not enough params: token');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const tokenData = await getToken({
|
|
17
|
+
uid: user?.uid || 0,
|
|
18
|
+
token: params.token,
|
|
19
|
+
json: 1,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
if (!tokenData) {
|
|
23
|
+
return reply.status(403).send('invalid params: token');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const { name: dirname } = tokenData;
|
|
27
|
+
|
|
28
|
+
// upload assets
|
|
29
|
+
if (req.headers['content-type']?.split?.(';')?.shift?.() === 'multipart/form-data') {
|
|
30
|
+
const file = await uploadMultiPart(req);
|
|
31
|
+
const filename = `${file.newFilename}${path.extname(file.filepath)}`;
|
|
32
|
+
const newfilepath = path.join(rootDir, 'media', dirname || '', filename);
|
|
33
|
+
// console.log(file.filepath, newfilepath);
|
|
34
|
+
await rename(file.filepath, newfilepath);
|
|
35
|
+
|
|
36
|
+
const id = await dataInsert({
|
|
37
|
+
table: 'crm.media',
|
|
38
|
+
data: {
|
|
39
|
+
uploaded_name: file.originalFilename,
|
|
40
|
+
file_path: path.join('/media', dirname || '', filename).replace(/\\/g, '/'),
|
|
41
|
+
ext: path.extname(file.filepath)?.split('.')?.pop?.(),
|
|
42
|
+
size: file.size,
|
|
43
|
+
},
|
|
44
|
+
uid: user?.uid || 0,
|
|
45
|
+
}).then(el => el?.rows?.[0]?.media_id);
|
|
46
|
+
const result = {
|
|
47
|
+
dir: dirname,
|
|
48
|
+
id,
|
|
49
|
+
name: filename,
|
|
50
|
+
type: 'file',
|
|
51
|
+
token: setToken({
|
|
52
|
+
ids: [JSON.stringify({ id, dir: dirname, relpath: path.join('/media', dirname || '', filename).replace(/\\/g, '/'), name: filename, type: 'file' })],
|
|
53
|
+
uid: user?.uid || 0,
|
|
54
|
+
array: 1,
|
|
55
|
+
})[0],
|
|
56
|
+
};
|
|
57
|
+
return reply.status(200).send(result);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// create directory
|
|
61
|
+
if (!body?.name || typeof body.name !== 'string' || body.name.includes('..')) {
|
|
62
|
+
return reply.status(400).send('invalid body params: name');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const subdir = path.join('/media', dirname || '', body.name).replace(/\\/g, '/');
|
|
66
|
+
const dirpath = path.join(rootDir, subdir);
|
|
67
|
+
await mkdir(dirpath, { recursive: true });
|
|
68
|
+
|
|
69
|
+
return reply.status(200).send({
|
|
70
|
+
dir: subdir,
|
|
71
|
+
name: body.name,
|
|
72
|
+
type: 'dir',
|
|
73
|
+
token: setToken({
|
|
74
|
+
ids: [JSON.stringify({ relpath: subdir, name: body.name, type: 'dir' })],
|
|
75
|
+
uid: user?.uid || 0,
|
|
76
|
+
array: 1,
|
|
77
|
+
})[0],
|
|
78
|
+
});
|
|
79
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import list from './controllers/list.js';
|
|
2
|
+
import metadata from './controllers/metadata.js';
|
|
3
|
+
import upload from './controllers/upload.js';
|
|
4
|
+
import edit from './controllers/edit.js';
|
|
5
|
+
import del from './controllers/delete.js';
|
|
6
|
+
import preview from './controllers/preview.js';
|
|
7
|
+
|
|
8
|
+
export default async function route(app) {
|
|
9
|
+
app.get('/cms-media', { config: { policy: ['site'] } }, list);
|
|
10
|
+
app.get('/cms-media/:token', { config: { policy: ['site'] } }, preview);
|
|
11
|
+
app.post('/cms-media/:token', { config: { policy: ['site'] } }, upload); // upload file / create empty dir
|
|
12
|
+
|
|
13
|
+
app.get('/cms-media-metadata/:token', { config: { policy: ['site'] } }, metadata);
|
|
14
|
+
app.put('/cms-media/:token', { config: { policy: ['site'] } }, edit);
|
|
15
|
+
app.delete('/cms-media/:token', { config: { policy: ['site'] } }, del);
|
|
16
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const schema = {
|
|
4
|
+
querystring: {
|
|
5
|
+
name: { type: 'string', pattern: "^(\\d+)$" },
|
|
6
|
+
token: { type: 'string', pattern: "^(\\d+)$" },
|
|
7
|
+
},
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default async function (fastify, opts) {
|
|
11
|
+
fastify.get('/test', async function (request, reply) {
|
|
12
|
+
return { root: true }
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en" dir="">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<!-- scripts -->
|
|
6
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
7
|
+
</head>
|
|
8
|
+
|
|
9
|
+
<body class="bg-[#f3f4f6] flex items-center flex-1 w-full h-[100vh] overflow-x-hidden min-h-full ">
|
|
10
|
+
<main class="w-full">
|
|
11
|
+
<div class="flex w-full max-w-sm mx-auto overflow-hidden bg-white rounded-lg shadow-lg dark:bg-gray-800 lg:max-w-4xl">
|
|
12
|
+
<div class="hidden bg-cover lg:block lg:w-1/2 bg-center" style="background-image: url('https://nipo.gov.ua/wp-content/uploads/2023/02/Pro_nas_2301-768x512.jpg');"></div>
|
|
13
|
+
|
|
14
|
+
<div class="w-full px-6 py-8 md:px-8 lg:w-1/2">
|
|
15
|
+
<div class="flex justify-center mx-auto">
|
|
16
|
+
<img class="w-auto h-7 sm:h-16" src="https://nipo.gov.ua/wp-content/uploads/2023/01/IP_office_logo_UA-1-1.png" alt="logo">
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<p class="mt-3 mb-[32px] text-xl text-center text-gray-600 dark:text-gray-200">
|
|
20
|
+
Український національний офіс інтелектуальної власності та інновацій
|
|
21
|
+
</p>
|
|
22
|
+
|
|
23
|
+
<form action="/api/login" method="get" >
|
|
24
|
+
<div class="mt-4">
|
|
25
|
+
<label class="block mb-2 text-sm font-medium text-gray-600 dark:text-gray-200" for="LoggingEmailAddress">Електронна пошта / Логін</label>
|
|
26
|
+
<input name="username" id="LoggingEmailAddress" class="block w-full px-4 py-2 text-gray-700 bg-white border rounded-lg dark:bg-gray-800 dark:text-gray-300 dark:border-gray-600 focus:border-blue-400 focus:ring-opacity-40 dark:focus:border-blue-300 focus:outline-none focus:ring focus:ring-blue-300" type="text">
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<div class="mt-4">
|
|
30
|
+
<div class="flex justify-between">
|
|
31
|
+
<label class="block mb-2 text-sm font-medium text-gray-600 dark:text-gray-200" for="loggingPassword">Пароль</label>
|
|
32
|
+
<!-- <a class="text-xs text-gray-500 dark:text-gray-300 hover:underline">Forget Password?</a> -->
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<input id="loggingPassword" name="password" class="block w-full px-4 py-2 text-gray-700 bg-white border rounded-lg dark:bg-gray-800 dark:text-gray-300 dark:border-gray-600 focus:border-blue-400 focus:ring-opacity-40 dark:focus:border-blue-300 focus:outline-none focus:ring focus:ring-blue-300" type="password">
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
<div class="mt-6">
|
|
39
|
+
<button type="submit" class="w-full px-6 py-3 text-sm font-medium tracking-wide text-white capitalize transition-colors duration-300 transform bg-gray-800 rounded-lg hover:bg-gray-700 focus:outline-none focus:ring focus:ring-gray-300 focus:ring-opacity-50">
|
|
40
|
+
Увійти
|
|
41
|
+
</button>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
</form>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
</main>
|
|
48
|
+
|
|
49
|
+
</body>
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
<script>
|
|
53
|
+
const error = location.search.includes('wrong_pass')
|
|
54
|
+
if (error) {
|
|
55
|
+
document.getElementById('login_error').innerHTML = 'Не вірний користувач або пароль';
|
|
56
|
+
}
|
|
57
|
+
</script>
|
|
58
|
+
|
|
59
|
+
</html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
select category_id, title from site.categories
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
select content_type_id, name from site.content_types
|