@opengis/cms 0.0.43 → 0.0.45
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/{en-CzEziHMG.js → en-sWmaB9uu.js} +4 -1
- package/dist/index.js +6298 -16055
- package/dist/index.umd.cjs +80 -78
- package/dist/{uk-TyVZmyOZ.js → uk-rH4IPxG5.js} +5 -2
- package/module/cms/table/collection.default.table.json +15 -15
- package/module/cms/table/single.default.table.json +19 -17
- package/package.json +65 -65
- package/server/routes/cms/controllers/downloadMedia.js +53 -18
- package/server/routes/cms/controllers/getPermissions.js +15 -15
- package/server/routes/cms/controllers/listMedia.js +39 -25
- package/server/routes/cms/controllers/setPermissions.js +49 -49
- package/server/templates/select/core.user_mentioned.sql +1 -1
- package/dist/index-W-qQIppj-DRzFSjU1.js +0 -2452
|
@@ -43,7 +43,8 @@ const e = {
|
|
|
43
43
|
general: "Основні",
|
|
44
44
|
apiKeys: "API ключі",
|
|
45
45
|
appearance: "Вигляд",
|
|
46
|
-
logs: "Логи"
|
|
46
|
+
logs: "Логи",
|
|
47
|
+
cms: "ЦМС"
|
|
47
48
|
},
|
|
48
49
|
dashboard: {
|
|
49
50
|
title: "Панель керування",
|
|
@@ -316,7 +317,8 @@ const e = {
|
|
|
316
317
|
localization: "Локалізація",
|
|
317
318
|
actions: "Дії",
|
|
318
319
|
noColumnsFound: "Немає колонок",
|
|
319
|
-
editCollection: "Редагувати
|
|
320
|
+
editCollection: "Редагувати структуру",
|
|
321
|
+
editPage: "Редагувати сторінку",
|
|
320
322
|
editContentForYourSite: "Редагувати контент для вашого сайту",
|
|
321
323
|
deleteObject: "Ви впевнені, що хочете видалити цей об'єкт?",
|
|
322
324
|
editField: "Редагувати поле",
|
|
@@ -484,6 +486,7 @@ const e = {
|
|
|
484
486
|
contacts: "Контакти",
|
|
485
487
|
socials: "Соціальні мережі",
|
|
486
488
|
showSocialsNumber: "Кількість соціальних мереж для відображення",
|
|
489
|
+
headerBtn: "Текст кнопки в хедері",
|
|
487
490
|
mapCoords: "Координати для відображення на карті",
|
|
488
491
|
saveChanges: "Зберегти зміни",
|
|
489
492
|
cancel: "Скасувати",
|
|
@@ -2,46 +2,46 @@
|
|
|
2
2
|
"table": "site.contents",
|
|
3
3
|
"columns": [
|
|
4
4
|
{
|
|
5
|
-
"label": "
|
|
6
|
-
"name": "slug",
|
|
7
|
-
"parent": "title",
|
|
8
|
-
"required": true,
|
|
9
|
-
"type": "slug"
|
|
10
|
-
},
|
|
11
|
-
{
|
|
12
|
-
"label": "Title",
|
|
5
|
+
"label": "Заголовок",
|
|
13
6
|
"name": "title",
|
|
14
7
|
"required": true,
|
|
15
8
|
"type": "text",
|
|
16
9
|
"localization": true
|
|
17
10
|
},
|
|
18
11
|
{
|
|
19
|
-
"label": "
|
|
12
|
+
"label": "Посилання",
|
|
13
|
+
"name": "slug",
|
|
14
|
+
"parent": "title",
|
|
15
|
+
"required": true,
|
|
16
|
+
"type": "slug"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"label": "Статус",
|
|
20
20
|
"name": "status",
|
|
21
21
|
"type": "select",
|
|
22
22
|
"data": "content.status",
|
|
23
23
|
"options": [
|
|
24
24
|
{
|
|
25
25
|
"id": "draft",
|
|
26
|
-
"text": "
|
|
26
|
+
"text": "Чернетка"
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
29
|
"id": "published",
|
|
30
|
-
"text": "
|
|
30
|
+
"text": "Опубліковано"
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
33
|
"id": "archived",
|
|
34
|
-
"text": "
|
|
34
|
+
"text": "Архівовано"
|
|
35
35
|
},
|
|
36
36
|
{
|
|
37
37
|
"id": "delayPublished",
|
|
38
|
-
"text": "
|
|
38
|
+
"text": "Відкладена публікація"
|
|
39
39
|
}
|
|
40
40
|
],
|
|
41
41
|
"required": true
|
|
42
42
|
},
|
|
43
43
|
{
|
|
44
|
-
"label": "
|
|
44
|
+
"label": "Дата публікації",
|
|
45
45
|
"name": "published_at",
|
|
46
46
|
"required": true,
|
|
47
47
|
"type": "datetime"
|
|
@@ -93,4 +93,4 @@
|
|
|
93
93
|
"ua": "Дата створення"
|
|
94
94
|
}
|
|
95
95
|
]
|
|
96
|
-
}
|
|
96
|
+
}
|
|
@@ -2,46 +2,46 @@
|
|
|
2
2
|
"table": "site.contents",
|
|
3
3
|
"columns": [
|
|
4
4
|
{
|
|
5
|
-
"label": "
|
|
6
|
-
"name": "slug",
|
|
7
|
-
"parent": "title",
|
|
8
|
-
"required": true,
|
|
9
|
-
"type": "slug"
|
|
10
|
-
},
|
|
11
|
-
{
|
|
12
|
-
"label": "Title",
|
|
5
|
+
"label": "Заголовок",
|
|
13
6
|
"name": "title",
|
|
14
7
|
"required": true,
|
|
15
8
|
"type": "text",
|
|
16
9
|
"localization": true
|
|
17
10
|
},
|
|
18
11
|
{
|
|
19
|
-
"label": "
|
|
12
|
+
"label": "Посилання",
|
|
13
|
+
"name": "slug",
|
|
14
|
+
"parent": "title",
|
|
15
|
+
"required": true,
|
|
16
|
+
"type": "slug"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"label": "Статус",
|
|
20
20
|
"name": "status",
|
|
21
21
|
"type": "select",
|
|
22
22
|
"data": "content.status",
|
|
23
23
|
"options": [
|
|
24
24
|
{
|
|
25
25
|
"id": "draft",
|
|
26
|
-
"text": "
|
|
26
|
+
"text": "Чернетка"
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
29
|
"id": "published",
|
|
30
|
-
"text": "
|
|
30
|
+
"text": "Опубліковано"
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
33
|
"id": "archived",
|
|
34
|
-
"text": "
|
|
34
|
+
"text": "Архівовано"
|
|
35
35
|
},
|
|
36
36
|
{
|
|
37
37
|
"id": "delayPublished",
|
|
38
|
-
"text": "
|
|
38
|
+
"text": "Відкладена публікація"
|
|
39
39
|
}
|
|
40
40
|
],
|
|
41
41
|
"required": true
|
|
42
42
|
},
|
|
43
43
|
{
|
|
44
|
-
"label": "
|
|
44
|
+
"label": "Дата публікації",
|
|
45
45
|
"name": "published_at",
|
|
46
46
|
"required": true,
|
|
47
47
|
"type": "datetime"
|
|
@@ -82,8 +82,10 @@
|
|
|
82
82
|
},
|
|
83
83
|
{
|
|
84
84
|
"extra": false,
|
|
85
|
-
"
|
|
86
|
-
"
|
|
85
|
+
"placeholder": "Пошук по тексту",
|
|
86
|
+
"label": "Пошук по тексту",
|
|
87
|
+
"columns": "slug,title",
|
|
88
|
+
"name": "search",
|
|
87
89
|
"type": "Text"
|
|
88
90
|
},
|
|
89
91
|
{
|
|
@@ -111,4 +113,4 @@
|
|
|
111
113
|
"ua": "Дата створення"
|
|
112
114
|
}
|
|
113
115
|
]
|
|
114
|
-
}
|
|
116
|
+
}
|
package/package.json
CHANGED
|
@@ -1,65 +1,65 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@opengis/cms",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "cms",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"author": "Softpro",
|
|
7
|
-
"main": "./dist/index.js",
|
|
8
|
-
"license": "EULA",
|
|
9
|
-
"files": [
|
|
10
|
-
"module",
|
|
11
|
-
"dist",
|
|
12
|
-
"server",
|
|
13
|
-
"plugin.js",
|
|
14
|
-
"input-types.json"
|
|
15
|
-
],
|
|
16
|
-
"scripts": {
|
|
17
|
-
"patch": "npm version patch && git push && npm publish",
|
|
18
|
-
"test": "node --test test/**/*.test.js",
|
|
19
|
-
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
|
|
20
|
-
"dev": "NODE_ENV=dev bun --env-file=.env.
|
|
21
|
-
"admin": "vite admin",
|
|
22
|
-
"build": "vite build && vite build admin",
|
|
23
|
-
"build:lib": "vite build",
|
|
24
|
-
"proxy": "vite dev admin",
|
|
25
|
-
"start": "bun --env-file=.env.ip server",
|
|
26
|
-
"prod": "NODE_ENV=production bun --env-file=.env.ip server ",
|
|
27
|
-
"ip": "bun --env-file=.env.ip server",
|
|
28
|
-
"demo": "node --env-file=.env.demo --env-file=.env server",
|
|
29
|
-
"i18n:sync": "node i18n-sync.cjs",
|
|
30
|
-
"prepublishOnly": "bun build:lib",
|
|
31
|
-
"softpro": "bun --env-file=.env.softpro server",
|
|
32
|
-
"softpro1": "NODE_ENV=production bun --env-file=.env.prod-softpro.local server"
|
|
33
|
-
},
|
|
34
|
-
"dependencies": {},
|
|
35
|
-
"resolutions": {
|
|
36
|
-
"rollup": "4.30.0"
|
|
37
|
-
},
|
|
38
|
-
"devDependencies": {
|
|
39
|
-
"@fastify/compress": "^8.1.0",
|
|
40
|
-
"@opengis/core": "^0.0.30",
|
|
41
|
-
"@opengis/fastify-table": "^2.0.128",
|
|
42
|
-
"@opengis/filter": "^0.1.
|
|
43
|
-
"@opengis/form": "^0.0.
|
|
44
|
-
"@opengis/richtext": "0.0.38",
|
|
45
|
-
"@vueuse/head": "2.0.0",
|
|
46
|
-
"js-yaml": "^4.1.0",
|
|
47
|
-
"lucide-vue-next": "0.344.0",
|
|
48
|
-
"vite": "5.1.4",
|
|
49
|
-
"vue": "^3.5.17",
|
|
50
|
-
"vue-i18n": "11.1.5",
|
|
51
|
-
"vue-router": "4.4.3",
|
|
52
|
-
"vuedraggable": "4.1.0",
|
|
53
|
-
"@tailwindcss/typography": "0.5.10",
|
|
54
|
-
"@tsconfig/node22": "^22.0.2",
|
|
55
|
-
"@vitejs/plugin-vue": "5.0.4",
|
|
56
|
-
"autoprefixer": "10.4.18",
|
|
57
|
-
"eslint": "8.49.0",
|
|
58
|
-
"postcss": "8.4.35",
|
|
59
|
-
"sass": "^1.92.1",
|
|
60
|
-
"tailwindcss": "3.4.1",
|
|
61
|
-
"typescript": "~5.8.0",
|
|
62
|
-
"vitest": "3.2.4",
|
|
63
|
-
"vue-tsc": "^2.2.10"
|
|
64
|
-
}
|
|
65
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@opengis/cms",
|
|
3
|
+
"version": "0.0.45",
|
|
4
|
+
"description": "cms",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"author": "Softpro",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"license": "EULA",
|
|
9
|
+
"files": [
|
|
10
|
+
"module",
|
|
11
|
+
"dist",
|
|
12
|
+
"server",
|
|
13
|
+
"plugin.js",
|
|
14
|
+
"input-types.json"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"patch": "npm version patch && git push && npm publish",
|
|
18
|
+
"test": "node --test test/**/*.test.js",
|
|
19
|
+
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
|
|
20
|
+
"dev": "NODE_ENV=dev bun --env-file=.env.ip server ",
|
|
21
|
+
"admin": "vite admin",
|
|
22
|
+
"build": "vite build && vite build admin",
|
|
23
|
+
"build:lib": "vite build",
|
|
24
|
+
"proxy": "vite dev admin",
|
|
25
|
+
"start": "bun --env-file=.env.ip server",
|
|
26
|
+
"prod": "NODE_ENV=production bun --env-file=.env.ip server ",
|
|
27
|
+
"ip": "bun --env-file=.env.ip server",
|
|
28
|
+
"demo": "node --env-file=.env.demo --env-file=.env server",
|
|
29
|
+
"i18n:sync": "node i18n-sync.cjs",
|
|
30
|
+
"prepublishOnly": "bun build:lib",
|
|
31
|
+
"softpro": "bun --env-file=.env.softpro server",
|
|
32
|
+
"softpro1": "NODE_ENV=production bun --env-file=.env.prod-softpro.local server"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {},
|
|
35
|
+
"resolutions": {
|
|
36
|
+
"rollup": "4.30.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@fastify/compress": "^8.1.0",
|
|
40
|
+
"@opengis/core": "^0.0.30",
|
|
41
|
+
"@opengis/fastify-table": "^2.0.128",
|
|
42
|
+
"@opengis/filter": "^0.1.31",
|
|
43
|
+
"@opengis/form": "^0.0.108",
|
|
44
|
+
"@opengis/richtext": "0.0.38",
|
|
45
|
+
"@vueuse/head": "2.0.0",
|
|
46
|
+
"js-yaml": "^4.1.0",
|
|
47
|
+
"lucide-vue-next": "0.344.0",
|
|
48
|
+
"vite": "5.1.4",
|
|
49
|
+
"vue": "^3.5.17",
|
|
50
|
+
"vue-i18n": "11.1.5",
|
|
51
|
+
"vue-router": "4.4.3",
|
|
52
|
+
"vuedraggable": "4.1.0",
|
|
53
|
+
"@tailwindcss/typography": "0.5.10",
|
|
54
|
+
"@tsconfig/node22": "^22.0.2",
|
|
55
|
+
"@vitejs/plugin-vue": "5.0.4",
|
|
56
|
+
"autoprefixer": "10.4.18",
|
|
57
|
+
"eslint": "8.49.0",
|
|
58
|
+
"postcss": "8.4.35",
|
|
59
|
+
"sass": "^1.92.1",
|
|
60
|
+
"tailwindcss": "3.4.1",
|
|
61
|
+
"typescript": "~5.8.0",
|
|
62
|
+
"vitest": "3.2.4",
|
|
63
|
+
"vue-tsc": "^2.2.10"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -2,48 +2,83 @@ import path from 'node:path';
|
|
|
2
2
|
import { existsSync } from 'node:fs';
|
|
3
3
|
import { readFile } from 'node:fs/promises';
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import sharp from "sharp";
|
|
6
|
+
import { imageSize } from "image-size";
|
|
7
|
+
|
|
8
|
+
import { config, getFolder, pgClients, grpc, getMimeType } from "@opengis/fastify-table/utils.js";
|
|
9
|
+
|
|
10
|
+
const { resizeImage } = grpc();
|
|
6
11
|
|
|
7
12
|
// path.resolve() converts POSIX paths from getFolder to valid Windows paths (Bun/Node fs require this on Windows)
|
|
8
13
|
const rootDir = path.resolve(getFolder(config, 'local'));
|
|
9
14
|
|
|
15
|
+
const previewWidth = 200;
|
|
16
|
+
const resizeQuality = 75;
|
|
17
|
+
|
|
10
18
|
export default async function downloadMedia({
|
|
11
|
-
pg = pgClients.client, params = {},
|
|
19
|
+
pg = pgClients.client, params = {}, query,
|
|
12
20
|
}, reply) {
|
|
13
21
|
if (!params?.id) {
|
|
14
|
-
return reply.status(400).send('not enough params: id');
|
|
22
|
+
return reply.status(400).send({ error: 'not enough params: id', code: 400 });
|
|
15
23
|
}
|
|
16
24
|
|
|
17
25
|
if (!pg.pk?.['site.media']) {
|
|
18
|
-
return reply.status(404).send('table not found');
|
|
26
|
+
return reply.status(404).send({ error: 'table not found', code: 404 });
|
|
19
27
|
}
|
|
20
28
|
|
|
21
|
-
const
|
|
22
|
-
|
|
29
|
+
const media = await pg.query(
|
|
30
|
+
`select media_id as id, filename, mime, url from site.media where media_id = $1 and url is not null`,
|
|
23
31
|
[params.id],
|
|
24
32
|
).then(el => el.rows?.[0] || {});
|
|
25
33
|
|
|
26
|
-
if (!id) {
|
|
27
|
-
return reply.status(404).send('media not found: ' + params.id);
|
|
34
|
+
if (!media.id) {
|
|
35
|
+
// return reply.status(404).send('media not found: ' + params.id);
|
|
36
|
+
const decodedPath = Buffer.from(params.id, 'base64url').toString('utf-8');
|
|
37
|
+
Object.assign(media, { url: decodedPath, mime: getMimeType(decodedPath) });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (!media.url || media.url.includes('..')) {
|
|
41
|
+
return reply.status(403).send({ error: "wrong params", code: 403 });
|
|
28
42
|
}
|
|
29
43
|
|
|
30
|
-
const filepath = path.join(rootDir,
|
|
44
|
+
const filepath = path.join(rootDir, media.url);
|
|
31
45
|
|
|
32
46
|
if (!existsSync(filepath)) {
|
|
33
|
-
return reply.status(404).send('file not found');
|
|
47
|
+
return reply.status(404).send({ error: 'file not found', code: 404 });
|
|
34
48
|
}
|
|
35
49
|
|
|
36
50
|
const buffer = await readFile(filepath, { buffer: true });
|
|
51
|
+
const headers = { 'Content-Type': media.mime, 'Cache-Control': query.nocache ? 'no-store, no-cache, must-revalidate' : 'public, max-age=2592000' };
|
|
52
|
+
|
|
53
|
+
// without nocache - cache resized images for 30d
|
|
54
|
+
if (params.type === 'preview' && media.mime && media.mime.startsWith('image/') && !media.mime.endsWith('/svg+xml')) {
|
|
55
|
+
const { width, height } = imageSize(buffer) || {};
|
|
56
|
+
const ratio = width / height;
|
|
57
|
+
const resizeWidth = Math.min(previewWidth, width);
|
|
58
|
+
const resizeHeight = resizeWidth / ratio;
|
|
59
|
+
|
|
60
|
+
const { result } = await resizeImage({
|
|
61
|
+
base64: buffer.toString("base64"),
|
|
62
|
+
width: resizeWidth,
|
|
63
|
+
height: resizeHeight,
|
|
64
|
+
quality: resizeQuality,
|
|
65
|
+
});
|
|
66
|
+
if (media.mime && media.mime.endsWith('/webp')) {
|
|
67
|
+
const webp = await sharp(Buffer.from(result, "base64")).webp({ quality: resizeQuality }).toBuffer({ resolveWithObject: false });
|
|
68
|
+
return reply.headers(headers).send(webp);
|
|
69
|
+
}
|
|
70
|
+
return reply.headers(headers).send(Buffer.from(result, "base64"));
|
|
71
|
+
}
|
|
37
72
|
|
|
38
73
|
// skip xml load for preview
|
|
39
|
-
if (params.type === 'preview' && path.extname(
|
|
40
|
-
return reply
|
|
74
|
+
if (params.type === 'preview' && ['.xml'].includes(path.extname(filepath))) {
|
|
75
|
+
return reply
|
|
76
|
+
.headers({
|
|
77
|
+
'Content-Type': media.mime,
|
|
78
|
+
'Content-Disposition': `attachment; filename=${path.basename(filepath)}`,
|
|
79
|
+
})
|
|
80
|
+
.send(buffer);
|
|
41
81
|
}
|
|
42
82
|
|
|
43
|
-
return reply
|
|
44
|
-
.headers({
|
|
45
|
-
'Content-Type': mime,
|
|
46
|
-
'Content-Disposition': `attachment; filename=${filename || path.basename(filepath)}`,
|
|
47
|
-
})
|
|
48
|
-
.send(buffer);
|
|
83
|
+
return reply.headers(headers).send(buffer);
|
|
49
84
|
}
|
|
@@ -1,16 +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 };
|
|
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
16
|
}
|
|
@@ -9,6 +9,9 @@ import { createHash } from 'node:crypto';
|
|
|
9
9
|
const rootDir = path.resolve(getFolder(config, 'local'));
|
|
10
10
|
const dir = '/files';
|
|
11
11
|
|
|
12
|
+
const filesizeCache = {};
|
|
13
|
+
const previewWidth = 300;
|
|
14
|
+
|
|
12
15
|
mkdirSync(path.join(rootDir, dir), { recursive: true });
|
|
13
16
|
|
|
14
17
|
export default async function listMedia(req, reply) {
|
|
@@ -63,31 +66,42 @@ export default async function listMedia(req, reply) {
|
|
|
63
66
|
Object.assign(result, { rootDir });
|
|
64
67
|
}
|
|
65
68
|
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
69
|
+
const filteredFiles = (search ? allItems.filter(el => el.name.includes(search)) : items).filter(el => el.isFile());
|
|
70
|
+
|
|
71
|
+
const files = await Promise.all(filteredFiles.map(async el => {
|
|
72
|
+
const media = rows.find(row => row.filename === el.name);
|
|
73
|
+
const filepath = media ? media.url : ('/files/' + (el.path.split('/files/')[1] ? el.path.split('/files/')[1] + '/' : '') + el.name);
|
|
74
|
+
|
|
75
|
+
if (!filesizeCache[filepath]) {
|
|
76
|
+
const { size } = await stat(path.join(rootDir, filepath));
|
|
77
|
+
Object.assign(filesizeCache, { [filepath]: size });
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const mime = getMimeType(el.name) || '';
|
|
81
|
+
const preview = mime.startsWith('image/') /* && mime !== 'image/svg+xml' */
|
|
82
|
+
? `${req.routeOptions.url}/${media ? media.id : Buffer.from(filepath).toString('base64url')}/preview`
|
|
83
|
+
: undefined;
|
|
84
|
+
|
|
85
|
+
return media ? {
|
|
86
|
+
type: 'file',
|
|
87
|
+
...media,
|
|
88
|
+
url: `${req.routeOptions.url}/${media.id}/file`,
|
|
89
|
+
preview,
|
|
90
|
+
filepath,
|
|
91
|
+
metadata: `${req.routeOptions.url}/${media.id}`,
|
|
92
|
+
} : {
|
|
93
|
+
id: createHash('md5').update(filepath).digest('hex'),
|
|
94
|
+
hash: true,
|
|
95
|
+
type: 'file',
|
|
96
|
+
filename: el.name,
|
|
97
|
+
filepath,
|
|
98
|
+
filetype: mime.startsWith('image/') ? "image" : "other",
|
|
99
|
+
filesize: filesizeCache[filepath] || 0,
|
|
100
|
+
url: filepath,
|
|
101
|
+
mime,
|
|
102
|
+
preview,
|
|
103
|
+
}
|
|
104
|
+
}));
|
|
91
105
|
|
|
92
106
|
Object.assign(result, { data: subdirs.concat(files) });
|
|
93
107
|
return result;
|
|
@@ -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
|
}
|
|
@@ -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,'')
|