@opengis/fastify-table 1.4.28 → 1.4.30
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/config.js +6 -32
- package/index.js +7 -1
- package/package.json +3 -3
- package/server/plugins/cron/index.js +1 -1
- package/server/plugins/crud/funcs/dataDelete.js +40 -44
- package/server/plugins/crud/funcs/dataUpdate.js +4 -8
- package/server/plugins/file/isFileExists.js +2 -2
- package/server/plugins/file/uploadMultiPart.js +74 -35
- package/server/plugins/file/utils/getPath.js +1 -1
- package/server/plugins/file/utils/isFileExists.js +1 -0
- package/server/plugins/grpc/grpc.js +2 -1
- package/server/plugins/grpc/office2pdf.js +2 -1
- package/server/plugins/util/funcs/unflattenObject.js +17 -3
- package/server/routes/file/controllers/export.js +14 -8
- package/server/routes/file/controllers/utils/{convertJSONToXls.js → jsonToXls.js} +1 -2
- package/server/routes/menu/controllers/getMenu.js +4 -3
- package/server/routes/table/controllers/tableData.js +5 -3
- package/server/routes/table/functions/getData.js +17 -3
- package/utils.js +4 -0
- package/server/plugins/file/utils/uploadFileDisk.js +0 -87
- /package/server/routes/file/controllers/utils/{convertJSONToCSV.js → jsonToCsv.js} +0 -0
package/config.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import dotenv from 'dotenv';
|
|
2
|
-
import path from 'node:path';
|
|
3
2
|
|
|
4
3
|
import { existsSync, readFileSync } from 'node:fs';
|
|
5
4
|
|
|
@@ -8,46 +7,21 @@ import unflattenObject from './server/plugins/util/funcs/unflattenObject.js';
|
|
|
8
7
|
const fileName = ['config.json', '/data/local/config.json'].find(el => (existsSync(el) ? el : null));
|
|
9
8
|
const config = fileName ? JSON.parse(readFileSync(fileName)) : {};
|
|
10
9
|
|
|
10
|
+
const { skipKeys = ['windir'] } = config;
|
|
11
|
+
|
|
11
12
|
// npm run dev === cross-env NODE_ENV=development
|
|
12
13
|
// alt: node --env=development
|
|
13
14
|
Object.assign(config, {
|
|
14
15
|
storageList: {},
|
|
15
16
|
allTemplates: config?.allTemplates || {},
|
|
16
17
|
skipCheckPolicyRoutes: [],
|
|
17
|
-
env: process.env?.NODE_ENV
|
|
18
|
+
env: process.env?.NODE_ENV,
|
|
18
19
|
});
|
|
19
20
|
|
|
20
21
|
function loadEnvConfig() {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
console.log('start with env:', config.env);
|
|
25
|
-
|
|
26
|
-
const obj = unflattenObject(parsed);
|
|
27
|
-
|
|
28
|
-
Object.keys(obj || {})
|
|
29
|
-
.filter(key => typeof obj[key] === 'string'
|
|
30
|
-
&& (obj[key].startsWith('[') || ['true', 'false'].includes(obj[key]))) // json array / boolean
|
|
31
|
-
.forEach(key => {
|
|
32
|
-
try {
|
|
33
|
-
obj[key] = JSON.parse(obj[key]);
|
|
34
|
-
}
|
|
35
|
-
catch (err) {
|
|
36
|
-
console.warn(`Invalid JSON for key "${key}": ${obj[key]}`);
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
if (obj) {
|
|
40
|
-
Object.assign(config, obj);
|
|
41
|
-
console.log('env init success', config.env, config.pg?.database);
|
|
42
|
-
}
|
|
43
|
-
else {
|
|
44
|
-
console.log('env init error', config.env, config.pg?.database);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
console.error('env init error: malformed file', config.env);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
22
|
+
// node --env-file-if-exists=.env.dev --env-file-if-exists=.env server
|
|
23
|
+
const configKeys = Object.keys(process.env).filter(key => !skipKeys.includes(key) && key.charAt(0) === key.charAt(0)?.toLowerCase?.() || key.includes('.')).reduce((acc, curr) => ({ ...acc, [curr]: process.env[curr] }), {});
|
|
24
|
+
Object.assign(config, unflattenObject(configKeys));
|
|
51
25
|
}
|
|
52
26
|
|
|
53
27
|
loadEnvConfig();
|
package/index.js
CHANGED
|
@@ -5,6 +5,8 @@ import { fileURLToPath } from 'node:url';
|
|
|
5
5
|
|
|
6
6
|
import config from './config.js';
|
|
7
7
|
|
|
8
|
+
const { maxFileSize = 512 } = config;
|
|
9
|
+
|
|
8
10
|
// helpers
|
|
9
11
|
// import helperPlugin from './server/helpers/index.js';
|
|
10
12
|
|
|
@@ -113,7 +115,11 @@ async function plugin(fastify, opt) {
|
|
|
113
115
|
templatesRoutes(fastify, opt);
|
|
114
116
|
|
|
115
117
|
// from fastify-file
|
|
116
|
-
await fastify.register(import('@fastify/multipart')
|
|
118
|
+
await fastify.register(import('@fastify/multipart'), {
|
|
119
|
+
limits: {
|
|
120
|
+
fileSize: maxFileSize * 1024 * 1024,
|
|
121
|
+
},
|
|
122
|
+
}); // content parser, await before adding upload routes
|
|
117
123
|
fastify.register(import('./server/routes/file/index.mjs'), opt);
|
|
118
124
|
fastify.register(import('./server/routes/grpc/index.mjs'), opt);
|
|
119
125
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengis/fastify-table",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.30",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "core-plugins",
|
|
6
6
|
"keywords": [
|
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
"test:routes": "node --test .\\test\\routes",
|
|
27
27
|
"test:functions": "node --test .\\test\\functions",
|
|
28
28
|
"compress": "node compress.js",
|
|
29
|
-
"
|
|
29
|
+
"dev1": "set NODE_ENV=dev&& node server.js",
|
|
30
|
+
"dev": "node --env-file=.env.dev --env-file=.env server"
|
|
30
31
|
},
|
|
31
32
|
"dependencies": {
|
|
32
33
|
"@aws-sdk/client-s3": "3.554.0",
|
|
@@ -37,7 +38,6 @@
|
|
|
37
38
|
"dotenv": "16.5.0",
|
|
38
39
|
"fastify": "5.3.3",
|
|
39
40
|
"fastify-plugin": "5.0.1",
|
|
40
|
-
"formidable": "3.5.1",
|
|
41
41
|
"handlebars": "4.7.8",
|
|
42
42
|
"image-size": "1.2.0",
|
|
43
43
|
"ioredis": "5.3.2",
|
|
@@ -47,7 +47,7 @@ async function runCron({
|
|
|
47
47
|
|
|
48
48
|
async function plugin(fastify) {
|
|
49
49
|
if (config.cronList?.length) {
|
|
50
|
-
config.cronList?.filter(el => el.query && !el.disabled)?.forEach?.((el, idx) => {
|
|
50
|
+
config.cronList?.filter?.(el => el.query && !el.disabled)?.forEach?.((el, idx) => {
|
|
51
51
|
const { interval, db, query } = el;
|
|
52
52
|
const name = createHash('md5').update(`${config.port || 3000}:${db}:${query}`).digest('hex');
|
|
53
53
|
const pg = getPG(db);
|
|
@@ -32,59 +32,55 @@ export default async function dataDelete({
|
|
|
32
32
|
|
|
33
33
|
const delQuery = `delete from ${table} WHERE ${pk}::text = $1::text returning *`;
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
// for transactions
|
|
36
|
+
const isClient = typeof pg.query === 'function' && typeof pg.release === 'function';
|
|
37
|
+
const client = isClient ? pg : await pg.connect();
|
|
38
|
+
|
|
39
|
+
if (isClient || !client.pk) {
|
|
40
|
+
client.options = pg.options;
|
|
41
|
+
client.tlist = pg.tlist;
|
|
42
|
+
client.pgType = pg.pgType;
|
|
43
|
+
client.relkinds = pg.relkinds;
|
|
44
|
+
client.pk = pg.pk;
|
|
45
|
+
}
|
|
38
46
|
|
|
47
|
+
try {
|
|
39
48
|
if (!isClient) {
|
|
40
|
-
client.
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (isClient || !client.pk) {
|
|
44
|
-
client.options = pg.options;
|
|
45
|
-
client.tlist = pg.tlist;
|
|
46
|
-
client.pgType = pg.pgType;
|
|
47
|
-
client.relkinds = pg.relkinds;
|
|
48
|
-
client.pk = pg.pk;
|
|
49
|
+
await client.query('begin;');
|
|
49
50
|
}
|
|
50
51
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
const row = {};
|
|
53
|
+
await extraData({
|
|
54
|
+
table, form: tokenData?.form, id, uid, row,
|
|
55
|
+
}, client);
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
table, form: tokenData?.form, id, uid, row,
|
|
59
|
-
}, client);
|
|
57
|
+
const res = await client.query(delQuery, [id])
|
|
58
|
+
.then(el => (el.rows?.[0] ? { rowCount: 1, ...el.rows[0] } : {}));
|
|
60
59
|
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
await logChanges({
|
|
61
|
+
pg: client, table, tokenData, referer, id, uid, type: 'DELETE',
|
|
62
|
+
});
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
pg: client, table, tokenData, referer, id, uid, type: 'DELETE',
|
|
66
|
-
});
|
|
64
|
+
if (config.redis) { rclient.incr(`pg:${table}:crud`); }
|
|
67
65
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (client.caller === 'dataDelete') {
|
|
71
|
-
await client.query('commit;');
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return { ...res, ...row };
|
|
66
|
+
if (!isClient) {
|
|
67
|
+
await client.query('commit;');
|
|
75
68
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
69
|
+
|
|
70
|
+
return { ...res, ...row };
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
logger.file('crud/delete', {
|
|
74
|
+
error: err.toString(), stack: err.stack, table, id, referer, uid, form: tokenData?.form,
|
|
75
|
+
});
|
|
76
|
+
if (!isClient) {
|
|
77
|
+
await client.query('rollback;');
|
|
84
78
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
79
|
+
throw err;
|
|
80
|
+
}
|
|
81
|
+
finally {
|
|
82
|
+
if (!isClient) {
|
|
83
|
+
await client.query('begin;');
|
|
89
84
|
}
|
|
85
|
+
}
|
|
90
86
|
}
|
|
@@ -79,10 +79,6 @@ export default async function dataUpdate({
|
|
|
79
79
|
const isClient = typeof pg.query === 'function' && typeof pg.release === 'function';
|
|
80
80
|
const client = isClient ? pg : await pg.connect();
|
|
81
81
|
|
|
82
|
-
if (!isClient) {
|
|
83
|
-
client.caller = 'dataUpdate';
|
|
84
|
-
}
|
|
85
|
-
|
|
86
82
|
if (isClient || !client.pk) {
|
|
87
83
|
client.options = pg.options;
|
|
88
84
|
client.tlist = pg.tlist;
|
|
@@ -92,7 +88,7 @@ export default async function dataUpdate({
|
|
|
92
88
|
}
|
|
93
89
|
|
|
94
90
|
try {
|
|
95
|
-
if (
|
|
91
|
+
if (!isClient) {
|
|
96
92
|
await client.query('begin;');
|
|
97
93
|
}
|
|
98
94
|
const res = await client.query(updateQuery, [id, ...filterValue])
|
|
@@ -161,7 +157,7 @@ export default async function dataUpdate({
|
|
|
161
157
|
|
|
162
158
|
if (config.redis) { rclient.incr(`pg:${table}:crud`); }
|
|
163
159
|
|
|
164
|
-
if (
|
|
160
|
+
if (!isClient) {
|
|
165
161
|
await client.query('commit;');
|
|
166
162
|
}
|
|
167
163
|
return res || {};
|
|
@@ -170,13 +166,13 @@ export default async function dataUpdate({
|
|
|
170
166
|
logger.file('crud/update', {
|
|
171
167
|
error: err.toString(), stack: err.stack, table, id, referer, uid, form: tokenData?.form,
|
|
172
168
|
});
|
|
173
|
-
if (
|
|
169
|
+
if (!isClient) {
|
|
174
170
|
await client.query('rollback;');
|
|
175
171
|
}
|
|
176
172
|
throw err;
|
|
177
173
|
}
|
|
178
174
|
finally {
|
|
179
|
-
if (
|
|
175
|
+
if (!isClient) {
|
|
180
176
|
client.release();
|
|
181
177
|
}
|
|
182
178
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import path from 'path';
|
|
1
|
+
import path from 'node:path';
|
|
2
2
|
import providers from './providers/index.js';
|
|
3
3
|
|
|
4
|
-
async function isFileExists(filePath, options = {
|
|
4
|
+
async function isFileExists(filePath, options = {}) {
|
|
5
5
|
const filename = path.basename(filePath);
|
|
6
6
|
|
|
7
7
|
// prefix
|
|
@@ -1,61 +1,100 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import { mkdir } from 'node:fs/promises';
|
|
2
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
4
|
+
import { imageSize } from 'image-size';
|
|
3
5
|
|
|
4
|
-
import
|
|
6
|
+
import config from '../../../config.js';
|
|
5
7
|
|
|
6
8
|
import providers from './providers/index.js';
|
|
7
|
-
import uploadFileDisk from './utils/uploadFileDisk.js';
|
|
8
9
|
|
|
9
10
|
import { all, images } from './utils/allowedExtensions.js';
|
|
10
11
|
|
|
12
|
+
import grpc from '../grpc/grpc.js';
|
|
13
|
+
|
|
14
|
+
const { resizeImage } = grpc();
|
|
15
|
+
|
|
16
|
+
const { resizeImageMinSize = 5 } = config; // resize images >= 5 MB by default
|
|
17
|
+
|
|
18
|
+
async function writeFileToDisk(file, buffer) {
|
|
19
|
+
if (!file?.filepath || !file.extension || !buffer) { return null; }
|
|
20
|
+
|
|
21
|
+
// resize big images
|
|
22
|
+
if (images.find(el => el === file.extension) && file.size >= (resizeImageMinSize * 1024 * 1024)) {
|
|
23
|
+
const { width = 320, height = 240 } = imageSize(buffer) || {};
|
|
24
|
+
|
|
25
|
+
const ratio = width / height;
|
|
26
|
+
|
|
27
|
+
const resizeWidth = Math.min(width, 2048);
|
|
28
|
+
const resizeHeight = resizeWidth / ratio;
|
|
29
|
+
|
|
30
|
+
const { result } = await resizeImage({
|
|
31
|
+
base64: buffer.toString('base64'),
|
|
32
|
+
width: resizeWidth,
|
|
33
|
+
height: resizeHeight,
|
|
34
|
+
quality: 75,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
await writeFile(`${file.filepath.replace(`.${file.extension}`, `_original.${file.extension}`)}`, buffer);
|
|
38
|
+
await writeFile(file.filepath, Buffer.from(result, 'base64'));
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
await writeFile(file.filepath, buffer);
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
11
46
|
export default async function uploadMultiPart(req) {
|
|
12
47
|
const allowedExtensions = {
|
|
13
48
|
'/file/upload-image/*': images,
|
|
14
49
|
}[req.routeOptions?.url || ''] || all;
|
|
15
50
|
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const dbname = req.pg?.options?.database || req.pg?.database || config.pg?.database; // request / config params / default config params
|
|
19
|
-
const folder = path.join(config.root || `/data/local/${dbname || ''}`, config.folder || '', 'files', dir, yearMonthDay);
|
|
20
|
-
await mkdir(folder, { recursive: true });
|
|
21
|
-
|
|
22
|
-
const file = await uploadFileDisk({ req, folder }) || {};
|
|
23
|
-
if (!file?.filepath) throw new Error('upload error');
|
|
51
|
+
const parts = req.parts();
|
|
52
|
+
const part = await parts.next();
|
|
24
53
|
|
|
25
|
-
|
|
26
|
-
|
|
54
|
+
if (!part?.value?.filename) {
|
|
55
|
+
throw new Error('upload error');
|
|
56
|
+
}
|
|
27
57
|
|
|
28
|
-
const
|
|
58
|
+
const ext = path.extname(part.value.filename).toLowerCase();
|
|
29
59
|
|
|
30
60
|
// check extension
|
|
31
|
-
if (allowedExtensions.
|
|
61
|
+
if (!allowedExtensions.includes(ext.substring(1))) {
|
|
32
62
|
throw new Error('file extension is not allowed');
|
|
33
63
|
}
|
|
34
64
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
65
|
+
const buffer = await part.value.toBuffer();
|
|
66
|
+
|
|
67
|
+
if (!buffer?.length) {
|
|
68
|
+
throw new Error('file buffer is empty');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const dir = req.params?.['*'] || 'uploads';
|
|
72
|
+
const yearMonthDay = (new Date()).toISOString().split('T')[0];
|
|
73
|
+
|
|
74
|
+
const dbname = req.pg?.options?.database || req.pg?.database || config.pg?.database; // request / config params / default config params
|
|
75
|
+
|
|
76
|
+
const rootDir = config.root || `/data/local/${dbname || ''}`;
|
|
77
|
+
const reldirpath = path.join('/files', dir, yearMonthDay);
|
|
78
|
+
const folder = path.join(rootDir, config.folder || '', reldirpath);
|
|
79
|
+
|
|
80
|
+
const newFilename = `${randomUUID()}${ext}`;
|
|
81
|
+
|
|
82
|
+
const file = {
|
|
83
|
+
originalFilename: part.value.filename,
|
|
84
|
+
filepath: path.join(folder, newFilename).replace(/\\/g, '/'),
|
|
85
|
+
relativeFilepath: path.join(reldirpath, newFilename).replace(/\\/g, '/'),
|
|
86
|
+
size: Buffer.byteLength(buffer),
|
|
87
|
+
mimetype: part.value.mimetype,
|
|
88
|
+
extension: ext.substring(1),
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
await mkdir(folder, { recursive: true });
|
|
92
|
+
await writeFileToDisk(file, buffer);
|
|
50
93
|
|
|
51
94
|
// move file to s3
|
|
52
95
|
if (config.s3?.endpoint) {
|
|
53
|
-
const fp = providers({ provider: 'fs' });
|
|
54
|
-
const data = await fp.downloadFile(filepath, { buffer: true });
|
|
55
|
-
if (typeof data === 'function') throw new Error('data is function!');
|
|
56
|
-
if (!data) throw new Error('upload error');
|
|
57
96
|
const s3 = providers();
|
|
58
|
-
await s3.uploadFile(file.relativeFilepath,
|
|
97
|
+
await s3.uploadFile(file.relativeFilepath, buffer);
|
|
59
98
|
if (config.trace) console.log('upload to s3', file.relativeFilepath);
|
|
60
99
|
}
|
|
61
100
|
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
import grpc from '@grpc/grpc-js';
|
|
3
3
|
import protoLoader from '@grpc/proto-loader';
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import config from '../../../config.js';
|
|
6
|
+
import logger from '../logger/getLogger.js';
|
|
6
7
|
|
|
7
8
|
config.ready = config.ready || {};
|
|
8
9
|
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
import grpc from '@grpc/grpc-js';
|
|
3
3
|
import protoLoader from '@grpc/proto-loader';
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import config from '../../../config.js';
|
|
6
|
+
import logger from '../logger/getLogger.js';
|
|
6
7
|
|
|
7
8
|
config.ready = config.ready || {};
|
|
8
9
|
|
|
@@ -1,14 +1,28 @@
|
|
|
1
|
+
/* eslint-disable no-param-reassign */
|
|
1
2
|
export default function unflattenObject(flatObj) {
|
|
2
3
|
return Object.keys(flatObj).reduce((acc, key) => {
|
|
3
4
|
const keys = key.split('.');
|
|
4
5
|
keys.reduce((nestedObj, part, index) => {
|
|
5
6
|
if (index === keys.length - 1) {
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
// json array
|
|
8
|
+
if (typeof flatObj[key] === 'string' && flatObj[key].startsWith('[')) {
|
|
9
|
+
try {
|
|
10
|
+
nestedObj[part] = JSON.parse(flatObj[key]);
|
|
11
|
+
}
|
|
12
|
+
catch (err) {
|
|
13
|
+
console.error(`Error parsing JSON for key ${key}:`, err);
|
|
14
|
+
nestedObj[part] = flatObj[key]; // fallback to original value if parsing fails
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
nestedObj[part] = ['true', 'false'].includes(flatObj[key]) ? JSON.parse(flatObj[key]) : flatObj[key];
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
8
22
|
nestedObj[part] = nestedObj[part] || {};
|
|
9
23
|
}
|
|
10
24
|
return nestedObj[part];
|
|
11
25
|
}, acc);
|
|
12
26
|
return acc;
|
|
13
27
|
}, {});
|
|
14
|
-
}
|
|
28
|
+
}
|
|
@@ -9,12 +9,18 @@ import {
|
|
|
9
9
|
mkdir, readFile, rm, writeFile,
|
|
10
10
|
} from 'node:fs/promises';
|
|
11
11
|
|
|
12
|
-
import
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
import
|
|
17
|
-
import
|
|
12
|
+
import config from '../../../../config.js';
|
|
13
|
+
import logger from '../../../plugins/logger/getLogger.js';
|
|
14
|
+
import getTemplate from '../../../plugins/table/funcs/getTemplate.js';
|
|
15
|
+
import getMeta from '../../../plugins/pg/funcs/getMeta.js';
|
|
16
|
+
import pgClients from '../../../plugins/pg/pgClients.js';
|
|
17
|
+
import eventStream from '../../../plugins/util/funcs/eventStream.js';
|
|
18
|
+
import getData from '../../table/functions/getData.js';
|
|
19
|
+
import getFolder from '../../../plugins/crud/funcs/utils/getFolder.js';
|
|
20
|
+
import metaFormat from '../../../plugins/table/funcs/metaFormat/index.js';
|
|
21
|
+
|
|
22
|
+
import jsonToXls from './utils/jsonToXls.js';
|
|
23
|
+
import jsonToCsv from './utils/jsonToCsv.js';
|
|
18
24
|
import formatResult from './utils/formatResult.js';
|
|
19
25
|
|
|
20
26
|
const startStreamWithTotal = 10000;
|
|
@@ -262,12 +268,12 @@ export default async function exportTable({
|
|
|
262
268
|
const resp = {};
|
|
263
269
|
|
|
264
270
|
if (format === 'csv') {
|
|
265
|
-
await
|
|
271
|
+
await jsonToCsv({
|
|
266
272
|
filePath: filePathJSON, send, colmodel, domain: host, source, columnList,
|
|
267
273
|
});
|
|
268
274
|
}
|
|
269
275
|
if (format === 'xlsx') {
|
|
270
|
-
await
|
|
276
|
+
await jsonToXls({
|
|
271
277
|
filePath: filePathJSON, send, colmodel, domain: host, source, resp,
|
|
272
278
|
});
|
|
273
279
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
3
3
|
|
|
4
|
-
import
|
|
5
|
-
|
|
4
|
+
import logger from '../../../../plugins/logger/getLogger.js';
|
|
6
5
|
import grpc from '../../../../plugins/grpc/grpc.js';
|
|
7
6
|
|
|
8
7
|
const { jsonToXls } = grpc();
|
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
import { join } from 'node:path';
|
|
5
5
|
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
6
6
|
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
import config from '../../../../config.js';
|
|
8
|
+
import pgClients from '../../../plugins/pg/pgClients.js';
|
|
9
|
+
import applyHook from '../../../plugins/hook/funcs/applyHook.js';
|
|
10
|
+
import menuDirs from '../../../plugins/table/funcs/menuDirs.js';
|
|
10
11
|
|
|
11
12
|
const menuCache = [];
|
|
12
13
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import getToken from '../../../plugins/crud/funcs/getToken.js';
|
|
2
|
+
import getOpt from '../../../plugins/crud/funcs/getOpt.js';
|
|
3
|
+
import getTemplate from '../../../plugins/table/funcs/getTemplate.js';
|
|
4
|
+
import getMeta from '../../../plugins/pg/funcs/getMeta.js';
|
|
5
|
+
import pgClients from '../../../plugins/pg/pgClients.js';
|
|
4
6
|
|
|
5
7
|
import getData from '../functions/getData.js';
|
|
6
8
|
|
|
@@ -1,6 +1,20 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import config from '../../../../config.js';
|
|
2
|
+
import { handlebars, handlebarsSync } from '../../../helpers/index.js';
|
|
3
|
+
|
|
4
|
+
import getFilterSQL from '../../../plugins/table/funcs/getFilterSQL/index.js';
|
|
5
|
+
import getAccess from '../../../plugins/crud/funcs/getAccess.js';
|
|
6
|
+
import setToken from '../../../plugins/crud/funcs/setToken.js';
|
|
7
|
+
import gisIRColumn from '../../../plugins/table/funcs/gisIRColumn.js';
|
|
8
|
+
import applyHook from '../../../plugins/hook/funcs/applyHook.js';
|
|
9
|
+
import getSelect from '../../../plugins/table/funcs/getSelect.js';
|
|
10
|
+
import setOpt from '../../../plugins/crud/funcs/setOpt.js';
|
|
11
|
+
import getOpt from '../../../plugins/crud/funcs/getOpt.js';
|
|
12
|
+
import getFilter from '../../../plugins/table/funcs/getFilter.js';
|
|
13
|
+
import logger from '../../../plugins/logger/getLogger.js';
|
|
14
|
+
import getTemplate from '../../../plugins/table/funcs/getTemplate.js';
|
|
15
|
+
import getMeta from '../../../plugins/pg/funcs/getMeta.js';
|
|
16
|
+
import pgClients from '../../../plugins/pg/pgClients.js';
|
|
17
|
+
import metaFormat from '../../../plugins/table/funcs/metaFormat/index.js';
|
|
4
18
|
|
|
5
19
|
import extraDataGet from '../../../plugins/extra/extraDataGet.js';
|
|
6
20
|
|
package/utils.js
CHANGED
|
@@ -101,6 +101,8 @@ import grpc from './server/plugins/grpc/grpc.js';
|
|
|
101
101
|
import file2json from './server/plugins/grpc/file2json.js';
|
|
102
102
|
import officeConverter from './server/plugins/grpc/office2pdf.js';
|
|
103
103
|
import getExport from './server/plugins/file/getExport.js';
|
|
104
|
+
import jsonToCsv from './server/routes/file/controllers/utils/jsonToCsv.js';
|
|
105
|
+
import jsonToXls from './server/routes/file/controllers/utils/jsonToXls.js';
|
|
104
106
|
|
|
105
107
|
export default null;
|
|
106
108
|
export {
|
|
@@ -196,4 +198,6 @@ export {
|
|
|
196
198
|
getExport,
|
|
197
199
|
officeConverter,
|
|
198
200
|
allowedExtensions,
|
|
201
|
+
jsonToCsv,
|
|
202
|
+
jsonToXls,
|
|
199
203
|
};
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import { rename, readFile, writeFile } from 'node:fs/promises';
|
|
3
|
-
|
|
4
|
-
import { formidable } from 'formidable';
|
|
5
|
-
import { imageSize } from 'image-size';
|
|
6
|
-
|
|
7
|
-
import { config } from '../../../../utils.js';
|
|
8
|
-
|
|
9
|
-
import { images } from './allowedExtensions.js';
|
|
10
|
-
import grpc from '../../grpc/grpc.js';
|
|
11
|
-
|
|
12
|
-
const { resizeImage } = grpc();
|
|
13
|
-
const { maxFileSize = 512 } = config;
|
|
14
|
-
|
|
15
|
-
async function handleImages(file) {
|
|
16
|
-
const ext = path.extname(file.originalFilename).toLowerCase();
|
|
17
|
-
if (images.find(el => el === ext.substring(1)) && file.size >= 5000000) {
|
|
18
|
-
const fileData = await readFile(file.filepath, { buffer: true });
|
|
19
|
-
const { width = 320, height = 240 } = imageSize(fileData) || {};
|
|
20
|
-
|
|
21
|
-
const ratio = width / height;
|
|
22
|
-
|
|
23
|
-
const resizeWidth = Math.min(width, 2048);
|
|
24
|
-
const resizeHeight = resizeWidth / ratio;
|
|
25
|
-
|
|
26
|
-
const { result } = await resizeImage({
|
|
27
|
-
base64: Buffer.from(fileData).toString('base64'),
|
|
28
|
-
width: resizeWidth,
|
|
29
|
-
height: resizeHeight,
|
|
30
|
-
quality: 75,
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
await rename(file.filepath, `${file.filepath}_original${ext}`);
|
|
34
|
-
await writeFile(file.filepath + ext, Buffer.from(result, 'base64'));
|
|
35
|
-
|
|
36
|
-
file.originalFilepath = `${file.filepath}_original${ext}`;
|
|
37
|
-
file.filepath += ext;
|
|
38
|
-
|
|
39
|
-
return file;
|
|
40
|
-
}
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function promisify(func) {
|
|
45
|
-
// eslint-disable-next-line func-names
|
|
46
|
-
return async function (request) {
|
|
47
|
-
return new Promise((resolve, reject) => {
|
|
48
|
-
func(request, (err, fields, files) => {
|
|
49
|
-
if (err) { reject(err); }
|
|
50
|
-
resolve({ fields, files });
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
/*
|
|
56
|
-
[{
|
|
57
|
-
filepath,
|
|
58
|
-
mimetype,
|
|
59
|
-
originalFilename,
|
|
60
|
-
size
|
|
61
|
-
}]
|
|
62
|
-
*/
|
|
63
|
-
async function upload({ req, folder }) {
|
|
64
|
-
const form = formidable({ uploadDir: folder, keepExtensions: false, maxFileSize: maxFileSize * 1024 * 1024 });
|
|
65
|
-
const parse = promisify(form.parse.bind(form));
|
|
66
|
-
|
|
67
|
-
const files = await parse(req.raw).then((data) => data.files);
|
|
68
|
-
|
|
69
|
-
if (!files?.file?.[0]) return {};
|
|
70
|
-
const file = files.file[0];
|
|
71
|
-
const ext = path.extname(file.originalFilename).toLowerCase();
|
|
72
|
-
|
|
73
|
-
// resize big images
|
|
74
|
-
const result = await handleImages(file);
|
|
75
|
-
if (result) {
|
|
76
|
-
return result;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// rename with ext, keepExtensions has bug if file with .
|
|
80
|
-
await rename(file.filepath, file.filepath + ext);
|
|
81
|
-
|
|
82
|
-
file.filepath += ext;
|
|
83
|
-
|
|
84
|
-
return file;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export default upload;
|
|
File without changes
|