@saltcorn/server 0.6.2-beta.1 → 0.6.2-beta.2
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/app.js +9 -13
- package/auth/admin.js +5 -22
- package/auth/roleadmin.js +6 -16
- package/auth/routes.js +23 -52
- package/locales/en.json +20 -1
- package/markup/admin.js +17 -0
- package/package.json +15 -8
- package/public/saltcorn.css +2 -2
- package/restart_watcher.js +11 -2
- package/routes/actions.js +1 -15
- package/routes/admin.js +6 -23
- package/routes/api.js +51 -60
- package/routes/config.js +0 -1
- package/routes/crashlog.js +1 -4
- package/routes/delete.js +1 -2
- package/routes/edit.js +1 -2
- package/routes/eventlog.js +2 -15
- package/routes/events.js +0 -1
- package/routes/fields.js +1 -9
- package/routes/files.js +144 -64
- package/routes/homepage.js +3 -0
- package/routes/infoarch.js +12 -19
- package/routes/library.js +1 -4
- package/routes/list.js +2 -5
- package/routes/menu.js +6 -8
- package/routes/packs.js +2 -8
- package/routes/page.js +1 -7
- package/routes/pageedit.js +18 -30
- package/routes/plugins.js +21 -34
- package/routes/scapi.js +155 -184
- package/routes/search.js +6 -10
- package/routes/settings.js +1 -2
- package/routes/tables.js +1 -22
- package/routes/tenant.js +1 -9
- package/routes/utils.js +19 -19
- package/routes/view.js +7 -5
- package/routes/viewedit.js +18 -29
- package/s3storage.js +167 -0
package/routes/tenant.js
CHANGED
|
@@ -35,7 +35,7 @@ const {
|
|
|
35
35
|
const db = require("@saltcorn/data/db");
|
|
36
36
|
const url = require("url");
|
|
37
37
|
const { loadAllPlugins, loadAndSaveNewPlugin } = require("../load_plugins");
|
|
38
|
-
const {
|
|
38
|
+
const { isAdmin, error_catcher } = require("./utils.js");
|
|
39
39
|
const User = require("@saltcorn/data/models/user");
|
|
40
40
|
const File = require("@saltcorn/data/models/file");
|
|
41
41
|
const {
|
|
@@ -115,7 +115,6 @@ const is_ip_address = (hostname) => {
|
|
|
115
115
|
*/
|
|
116
116
|
router.get(
|
|
117
117
|
"/create",
|
|
118
|
-
setTenant,
|
|
119
118
|
error_catcher(async (req, res) => {
|
|
120
119
|
if (
|
|
121
120
|
!db.is_it_multi_tenant() ||
|
|
@@ -207,7 +206,6 @@ const getNewURL = (req, subdomain) => {
|
|
|
207
206
|
*/
|
|
208
207
|
router.post(
|
|
209
208
|
"/create",
|
|
210
|
-
setTenant,
|
|
211
209
|
error_catcher(async (req, res) => {
|
|
212
210
|
// check that multi-tenancy is enabled
|
|
213
211
|
if (
|
|
@@ -306,7 +304,6 @@ router.post(
|
|
|
306
304
|
*/
|
|
307
305
|
router.get(
|
|
308
306
|
"/list",
|
|
309
|
-
setTenant,
|
|
310
307
|
isAdmin,
|
|
311
308
|
error_catcher(async (req, res) => {
|
|
312
309
|
if (
|
|
@@ -390,7 +387,6 @@ const tenant_settings_form = (req) =>
|
|
|
390
387
|
*/
|
|
391
388
|
router.get(
|
|
392
389
|
"/settings",
|
|
393
|
-
setTenant,
|
|
394
390
|
isAdmin,
|
|
395
391
|
error_catcher(async (req, res) => {
|
|
396
392
|
if (
|
|
@@ -425,7 +421,6 @@ router.get(
|
|
|
425
421
|
*/
|
|
426
422
|
router.post(
|
|
427
423
|
"/settings",
|
|
428
|
-
setTenant,
|
|
429
424
|
isAdmin,
|
|
430
425
|
error_catcher(async (req, res) => {
|
|
431
426
|
const form = await tenant_settings_form(req);
|
|
@@ -502,7 +497,6 @@ const get_tenant_info = async (subdomain) => {
|
|
|
502
497
|
*/
|
|
503
498
|
router.get(
|
|
504
499
|
"/info/:subdomain",
|
|
505
|
-
setTenant,
|
|
506
500
|
isAdmin,
|
|
507
501
|
error_catcher(async (req, res) => {
|
|
508
502
|
if (
|
|
@@ -648,7 +642,6 @@ router.get(
|
|
|
648
642
|
*/
|
|
649
643
|
router.post(
|
|
650
644
|
"/info/:subdomain",
|
|
651
|
-
setTenant,
|
|
652
645
|
isAdmin,
|
|
653
646
|
error_catcher(async (req, res) => {
|
|
654
647
|
if (
|
|
@@ -680,7 +673,6 @@ router.post(
|
|
|
680
673
|
*/
|
|
681
674
|
router.post(
|
|
682
675
|
"/delete/:sub",
|
|
683
|
-
setTenant,
|
|
684
676
|
isAdmin,
|
|
685
677
|
error_catcher(async (req, res) => {
|
|
686
678
|
if (
|
package/routes/utils.js
CHANGED
|
@@ -20,9 +20,9 @@ const { validateHeaderName, validateHeaderValue } = require("http");
|
|
|
20
20
|
const Crash = require("@saltcorn/data/models/crash");
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
|
-
* @param {object} req
|
|
24
|
-
* @param {object} res
|
|
25
|
-
* @param {function} next
|
|
23
|
+
* @param {object} req
|
|
24
|
+
* @param {object} res
|
|
25
|
+
* @param {function} next
|
|
26
26
|
* @returns {void}
|
|
27
27
|
*/
|
|
28
28
|
function loggedIn(req, res, next) {
|
|
@@ -35,9 +35,9 @@ function loggedIn(req, res, next) {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
-
* @param {object} req
|
|
39
|
-
* @param {object} res
|
|
40
|
-
* @param {function} next
|
|
38
|
+
* @param {object} req
|
|
39
|
+
* @param {object} res
|
|
40
|
+
* @param {function} next
|
|
41
41
|
* @returns {void}
|
|
42
42
|
*/
|
|
43
43
|
function isAdmin(req, res, next) {
|
|
@@ -54,8 +54,8 @@ function isAdmin(req, res, next) {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
|
-
* @param {object} req
|
|
58
|
-
* @param {object} res
|
|
57
|
+
* @param {object} req
|
|
58
|
+
* @param {object} res
|
|
59
59
|
* @param {string} state
|
|
60
60
|
* @returns {void}
|
|
61
61
|
*/
|
|
@@ -67,8 +67,8 @@ const setLanguage = (req, res, state) => {
|
|
|
67
67
|
};
|
|
68
68
|
|
|
69
69
|
/**
|
|
70
|
-
* @param {object} res
|
|
71
|
-
* @param {string} state
|
|
70
|
+
* @param {object} res
|
|
71
|
+
* @param {string} state
|
|
72
72
|
* @returns {void}
|
|
73
73
|
*/
|
|
74
74
|
const set_custom_http_headers = (res, state) => {
|
|
@@ -90,7 +90,7 @@ const set_custom_http_headers = (res, state) => {
|
|
|
90
90
|
};
|
|
91
91
|
|
|
92
92
|
/**
|
|
93
|
-
* @param {object} req
|
|
93
|
+
* @param {object} req
|
|
94
94
|
* @returns {string}
|
|
95
95
|
*/
|
|
96
96
|
const get_tenant_from_req = (req) => {
|
|
@@ -106,9 +106,9 @@ const get_tenant_from_req = (req) => {
|
|
|
106
106
|
};
|
|
107
107
|
|
|
108
108
|
/**
|
|
109
|
-
* @param {object} req
|
|
110
|
-
* @param {object} res
|
|
111
|
-
* @param {function} next
|
|
109
|
+
* @param {object} req
|
|
110
|
+
* @param {object} res
|
|
111
|
+
* @param {function} next
|
|
112
112
|
*/
|
|
113
113
|
const setTenant = (req, res, next) => {
|
|
114
114
|
if (db.is_it_multi_tenant()) {
|
|
@@ -141,7 +141,7 @@ const setTenant = (req, res, next) => {
|
|
|
141
141
|
};
|
|
142
142
|
|
|
143
143
|
/**
|
|
144
|
-
* @param {object} req
|
|
144
|
+
* @param {object} req
|
|
145
145
|
* @returns {input}
|
|
146
146
|
*/
|
|
147
147
|
const csrfField = (req) =>
|
|
@@ -152,7 +152,7 @@ const csrfField = (req) =>
|
|
|
152
152
|
});
|
|
153
153
|
|
|
154
154
|
/**
|
|
155
|
-
* @param {function} fn
|
|
155
|
+
* @param {function} fn
|
|
156
156
|
* @returns {function}
|
|
157
157
|
*/
|
|
158
158
|
const error_catcher = (fn) => (request, response, next) => {
|
|
@@ -160,8 +160,8 @@ const error_catcher = (fn) => (request, response, next) => {
|
|
|
160
160
|
};
|
|
161
161
|
|
|
162
162
|
/**
|
|
163
|
-
* @param {string|object} contents
|
|
164
|
-
* @param {string} viewname
|
|
163
|
+
* @param {string|object} contents
|
|
164
|
+
* @param {string} viewname
|
|
165
165
|
* @returns {string}
|
|
166
166
|
*/
|
|
167
167
|
const scan_for_page_title = (contents, viewname) => {
|
|
@@ -224,10 +224,10 @@ module.exports = {
|
|
|
224
224
|
csrfField,
|
|
225
225
|
loggedIn,
|
|
226
226
|
isAdmin,
|
|
227
|
-
setTenant,
|
|
228
227
|
get_base_url,
|
|
229
228
|
error_catcher,
|
|
230
229
|
scan_for_page_title,
|
|
231
230
|
getGitRevision,
|
|
232
231
|
getSessionStore,
|
|
232
|
+
setTenant,
|
|
233
233
|
};
|
package/routes/view.js
CHANGED
|
@@ -13,12 +13,12 @@ const Page = require("@saltcorn/data/models/page");
|
|
|
13
13
|
const { div, text, i, a } = require("@saltcorn/markup/tags");
|
|
14
14
|
const { renderForm, link } = require("@saltcorn/markup");
|
|
15
15
|
const {
|
|
16
|
-
setTenant,
|
|
17
16
|
isAdmin,
|
|
18
17
|
error_catcher,
|
|
19
18
|
scan_for_page_title,
|
|
20
19
|
} = require("../routes/utils.js");
|
|
21
20
|
const { add_edit_bar } = require("../markup/admin.js");
|
|
21
|
+
const { InvalidConfiguration } = require("@saltcorn/data/utils");
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* @type {object}
|
|
@@ -38,7 +38,6 @@ module.exports = router;
|
|
|
38
38
|
*/
|
|
39
39
|
router.get(
|
|
40
40
|
"/:viewname",
|
|
41
|
-
setTenant,
|
|
42
41
|
error_catcher(async (req, res) => {
|
|
43
42
|
const { viewname } = req.params;
|
|
44
43
|
|
|
@@ -82,7 +81,6 @@ router.get(
|
|
|
82
81
|
*/
|
|
83
82
|
router.post(
|
|
84
83
|
"/:viewname/preview",
|
|
85
|
-
setTenant,
|
|
86
84
|
isAdmin,
|
|
87
85
|
error_catcher(async (req, res) => {
|
|
88
86
|
const { viewname } = req.params;
|
|
@@ -120,7 +118,6 @@ router.post(
|
|
|
120
118
|
*/
|
|
121
119
|
router.post(
|
|
122
120
|
"/:viewname/:route",
|
|
123
|
-
setTenant,
|
|
124
121
|
error_catcher(async (req, res) => {
|
|
125
122
|
const { viewname, route } = req.params;
|
|
126
123
|
const role = req.isAuthenticated() ? req.user.role_id : 10;
|
|
@@ -146,7 +143,6 @@ router.post(
|
|
|
146
143
|
*/
|
|
147
144
|
router.post(
|
|
148
145
|
"/:viewname",
|
|
149
|
-
setTenant,
|
|
150
146
|
error_catcher(async (req, res) => {
|
|
151
147
|
const { viewname } = req.params;
|
|
152
148
|
const role = req.isAuthenticated() ? req.user.role_id : 10;
|
|
@@ -161,6 +157,12 @@ router.post(
|
|
|
161
157
|
) {
|
|
162
158
|
req.flash("danger", req.__("Not authorized"));
|
|
163
159
|
res.redirect("/");
|
|
160
|
+
} else if (!view.runPost) {
|
|
161
|
+
throw new InvalidConfiguration(
|
|
162
|
+
`View ${text(viewname)} with template ${
|
|
163
|
+
view.viewtemplate
|
|
164
|
+
} does not supply a POST handler`
|
|
165
|
+
);
|
|
164
166
|
} else {
|
|
165
167
|
await view.runPost(req.query, req.body, { res, req });
|
|
166
168
|
}
|
package/routes/viewedit.js
CHANGED
|
@@ -30,7 +30,7 @@ const {
|
|
|
30
30
|
} = require("@saltcorn/markup/tags");
|
|
31
31
|
|
|
32
32
|
const { getState } = require("@saltcorn/data/db/state");
|
|
33
|
-
const {
|
|
33
|
+
const { isAdmin, error_catcher } = require("./utils.js");
|
|
34
34
|
const Form = require("@saltcorn/data/models/form");
|
|
35
35
|
const Field = require("@saltcorn/data/models/field");
|
|
36
36
|
const Table = require("@saltcorn/data/models/table");
|
|
@@ -53,9 +53,9 @@ const router = new Router();
|
|
|
53
53
|
module.exports = router;
|
|
54
54
|
|
|
55
55
|
/**
|
|
56
|
-
* @param {object} view
|
|
57
|
-
* @param {object[]} roles
|
|
58
|
-
* @param {object} req
|
|
56
|
+
* @param {object} view
|
|
57
|
+
* @param {object[]} roles
|
|
58
|
+
* @param {object} req
|
|
59
59
|
* @returns {Form}
|
|
60
60
|
*/
|
|
61
61
|
const editViewRoleForm = (view, roles, req) =>
|
|
@@ -67,8 +67,8 @@ const editViewRoleForm = (view, roles, req) =>
|
|
|
67
67
|
});
|
|
68
68
|
|
|
69
69
|
/**
|
|
70
|
-
* @param {object} view
|
|
71
|
-
* @param {object} req
|
|
70
|
+
* @param {object} view
|
|
71
|
+
* @param {object} req
|
|
72
72
|
* @returns {div}
|
|
73
73
|
*/
|
|
74
74
|
const view_dropdown = (view, req) =>
|
|
@@ -115,7 +115,6 @@ const view_dropdown = (view, req) =>
|
|
|
115
115
|
*/
|
|
116
116
|
router.get(
|
|
117
117
|
"/",
|
|
118
|
-
setTenant,
|
|
119
118
|
isAdmin,
|
|
120
119
|
error_catcher(async (req, res) => {
|
|
121
120
|
var orderBy = "name";
|
|
@@ -218,19 +217,19 @@ router.get(
|
|
|
218
217
|
);
|
|
219
218
|
|
|
220
219
|
/**
|
|
221
|
-
* @param {object} o
|
|
222
|
-
* @param {function} f
|
|
220
|
+
* @param {object} o
|
|
221
|
+
* @param {function} f
|
|
223
222
|
* @returns {object}
|
|
224
223
|
*/
|
|
225
224
|
const mapObjectValues = (o, f) =>
|
|
226
225
|
Object.fromEntries(Object.entries(o).map(([k, v]) => [k, f(v)]));
|
|
227
226
|
|
|
228
227
|
/**
|
|
229
|
-
* @param {object} req
|
|
230
|
-
* @param {object} tableOptions
|
|
231
|
-
* @param {object[]} roles
|
|
232
|
-
* @param {object[]} pages
|
|
233
|
-
* @param {object} values
|
|
228
|
+
* @param {object} req
|
|
229
|
+
* @param {object} tableOptions
|
|
230
|
+
* @param {object[]} roles
|
|
231
|
+
* @param {object[]} pages
|
|
232
|
+
* @param {object} values
|
|
234
233
|
* @returns {Form}
|
|
235
234
|
*/
|
|
236
235
|
const viewForm = (req, tableOptions, roles, pages, values) => {
|
|
@@ -328,7 +327,6 @@ const viewForm = (req, tableOptions, roles, pages, values) => {
|
|
|
328
327
|
*/
|
|
329
328
|
router.get(
|
|
330
329
|
"/edit/:viewname",
|
|
331
|
-
setTenant,
|
|
332
330
|
isAdmin,
|
|
333
331
|
error_catcher(async (req, res) => {
|
|
334
332
|
const { viewname } = req.params;
|
|
@@ -376,7 +374,6 @@ router.get(
|
|
|
376
374
|
*/
|
|
377
375
|
router.get(
|
|
378
376
|
"/new",
|
|
379
|
-
setTenant,
|
|
380
377
|
isAdmin,
|
|
381
378
|
error_catcher(async (req, res) => {
|
|
382
379
|
const tables = await Table.find_with_external();
|
|
@@ -414,7 +411,6 @@ router.get(
|
|
|
414
411
|
*/
|
|
415
412
|
router.post(
|
|
416
413
|
"/save",
|
|
417
|
-
setTenant,
|
|
418
414
|
isAdmin,
|
|
419
415
|
error_catcher(async (req, res) => {
|
|
420
416
|
const tables = await Table.find_with_external();
|
|
@@ -484,11 +480,11 @@ router.post(
|
|
|
484
480
|
);
|
|
485
481
|
|
|
486
482
|
/**
|
|
487
|
-
* @param {object} view
|
|
488
|
-
* @param {Workflow} wf
|
|
489
|
-
* @param {object} wfres
|
|
490
|
-
* @param {object} req
|
|
491
|
-
* @param {object} res
|
|
483
|
+
* @param {object} view
|
|
484
|
+
* @param {Workflow} wf
|
|
485
|
+
* @param {object} wfres
|
|
486
|
+
* @param {object} req
|
|
487
|
+
* @param {object} res
|
|
492
488
|
* @returns {void}
|
|
493
489
|
*/
|
|
494
490
|
const respondWorkflow = (view, wf, wfres, req, res) => {
|
|
@@ -532,7 +528,6 @@ const respondWorkflow = (view, wf, wfres, req, res) => {
|
|
|
532
528
|
*/
|
|
533
529
|
router.get(
|
|
534
530
|
"/config/:name",
|
|
535
|
-
setTenant,
|
|
536
531
|
isAdmin,
|
|
537
532
|
error_catcher(async (req, res) => {
|
|
538
533
|
const { name } = req.params;
|
|
@@ -565,7 +560,6 @@ router.get(
|
|
|
565
560
|
*/
|
|
566
561
|
router.post(
|
|
567
562
|
"/config/:name",
|
|
568
|
-
setTenant,
|
|
569
563
|
isAdmin,
|
|
570
564
|
error_catcher(async (req, res) => {
|
|
571
565
|
const { name } = req.params;
|
|
@@ -585,7 +579,6 @@ router.post(
|
|
|
585
579
|
*/
|
|
586
580
|
router.post(
|
|
587
581
|
"/add-to-menu/:id",
|
|
588
|
-
setTenant,
|
|
589
582
|
isAdmin,
|
|
590
583
|
error_catcher(async (req, res) => {
|
|
591
584
|
const { id } = req.params;
|
|
@@ -615,7 +608,6 @@ router.post(
|
|
|
615
608
|
*/
|
|
616
609
|
router.post(
|
|
617
610
|
"/clone/:id",
|
|
618
|
-
setTenant,
|
|
619
611
|
isAdmin,
|
|
620
612
|
error_catcher(async (req, res) => {
|
|
621
613
|
const { id } = req.params;
|
|
@@ -637,7 +629,6 @@ router.post(
|
|
|
637
629
|
*/
|
|
638
630
|
router.post(
|
|
639
631
|
"/delete/:id",
|
|
640
|
-
setTenant,
|
|
641
632
|
isAdmin,
|
|
642
633
|
error_catcher(async (req, res) => {
|
|
643
634
|
const { id } = req.params;
|
|
@@ -655,7 +646,6 @@ router.post(
|
|
|
655
646
|
*/
|
|
656
647
|
router.post(
|
|
657
648
|
"/savebuilder/:id",
|
|
658
|
-
setTenant,
|
|
659
649
|
isAdmin,
|
|
660
650
|
error_catcher(async (req, res) => {
|
|
661
651
|
const { id } = req.params;
|
|
@@ -679,7 +669,6 @@ router.post(
|
|
|
679
669
|
*/
|
|
680
670
|
router.post(
|
|
681
671
|
"/setrole/:id",
|
|
682
|
-
setTenant,
|
|
683
672
|
isAdmin,
|
|
684
673
|
error_catcher(async (req, res) => {
|
|
685
674
|
const { id } = req.params;
|
package/s3storage.js
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
var aws = require("aws-sdk");
|
|
2
|
+
var express = require("express");
|
|
3
|
+
var multer = require("multer");
|
|
4
|
+
var multerS3 = require("multer-s3");
|
|
5
|
+
const { getState } = require("@saltcorn/data/db/state");
|
|
6
|
+
const fileUpload = require("express-fileupload");
|
|
7
|
+
const { v4: uuidv4 } = require("uuid");
|
|
8
|
+
const { create } = require("@saltcorn/data/models/file");
|
|
9
|
+
var contentDisposition = require("content-disposition");
|
|
10
|
+
|
|
11
|
+
function createS3Client() {
|
|
12
|
+
return new aws.S3({
|
|
13
|
+
secretAccessKey: getState().getConfig("storage_s3_access_secret"),
|
|
14
|
+
accessKeyId: getState().getConfig("storage_s3_access_key"),
|
|
15
|
+
region: getState().getConfig("storage_s3_region"),
|
|
16
|
+
endpoint: getState().getConfig("storage_s3_endpoint"),
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
module.exports = {
|
|
21
|
+
/**
|
|
22
|
+
* Selector for file upload handler middleware. It will dispatch the
|
|
23
|
+
* file upload handler to the engine specified in the configuration.
|
|
24
|
+
*
|
|
25
|
+
* @param {*} req
|
|
26
|
+
* @param {*} res
|
|
27
|
+
* @param {*} next
|
|
28
|
+
*/
|
|
29
|
+
middlewareSelect: async function (req, res, next) {
|
|
30
|
+
const useS3 = getState().getConfig("storage_s3_enabled");
|
|
31
|
+
if (useS3 === true) {
|
|
32
|
+
// Create S3 object
|
|
33
|
+
|
|
34
|
+
// Create multer function
|
|
35
|
+
const s3upload = multer({
|
|
36
|
+
storage: multerS3({
|
|
37
|
+
s3: createS3Client(),
|
|
38
|
+
bucket: getState().getConfig("storage_s3_bucket"),
|
|
39
|
+
metadata: function (req, file, cb) {
|
|
40
|
+
cb(null, { fieldName: file.fieldname });
|
|
41
|
+
},
|
|
42
|
+
key: function (req, file, cb) {
|
|
43
|
+
cb(null, "tmp/" + Date.now().toString() + uuidv4());
|
|
44
|
+
},
|
|
45
|
+
}),
|
|
46
|
+
}).any();
|
|
47
|
+
|
|
48
|
+
s3upload(req, res, next);
|
|
49
|
+
} else {
|
|
50
|
+
// Use regular file upload
|
|
51
|
+
fileUpload({
|
|
52
|
+
useTempFiles: true,
|
|
53
|
+
createParentPath: true,
|
|
54
|
+
tempFileDir: "/tmp/",
|
|
55
|
+
})(req, res, next);
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Transform the processed req.files into that is suitable with
|
|
61
|
+
* Saltcorn File interface. It must be run after the middlewareSelect
|
|
62
|
+
*
|
|
63
|
+
* @param {*} req
|
|
64
|
+
* @param {*} res
|
|
65
|
+
* @param {*} next
|
|
66
|
+
*/
|
|
67
|
+
middlewareTransform: async function (req, res, next) {
|
|
68
|
+
// If nothing to process or S3 is not enabled
|
|
69
|
+
const useS3 = getState().getConfig("storage_s3_enabled");
|
|
70
|
+
if (!req.files || !useS3) {
|
|
71
|
+
next();
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Create S3 object
|
|
76
|
+
var s3 = createS3Client();
|
|
77
|
+
const bucket = getState().getConfig("storage_s3_bucket");
|
|
78
|
+
|
|
79
|
+
let newFileObject = {};
|
|
80
|
+
for (const file of req.files) {
|
|
81
|
+
file.mv = (newpath) => {
|
|
82
|
+
return new Promise((resolve, reject) => {
|
|
83
|
+
s3.copyObject(
|
|
84
|
+
{
|
|
85
|
+
Bucket: bucket,
|
|
86
|
+
CopySource: bucket + "/" + file.key,
|
|
87
|
+
Key: newpath,
|
|
88
|
+
},
|
|
89
|
+
function (err, data) {
|
|
90
|
+
if (err) reject(err);
|
|
91
|
+
else {
|
|
92
|
+
// Then delete
|
|
93
|
+
s3.deleteObject(
|
|
94
|
+
{
|
|
95
|
+
Bucket: bucket,
|
|
96
|
+
Key: file.key,
|
|
97
|
+
},
|
|
98
|
+
(err, data) => {
|
|
99
|
+
if (err) reject(err);
|
|
100
|
+
else resolve(data);
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
});
|
|
107
|
+
};
|
|
108
|
+
file.s3object = true;
|
|
109
|
+
file.name = file.originalname;
|
|
110
|
+
newFileObject[file.fieldname] = file;
|
|
111
|
+
}
|
|
112
|
+
req.files = newFileObject;
|
|
113
|
+
next();
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Selector to serve object based on S3 state
|
|
118
|
+
*
|
|
119
|
+
* @param {*} file
|
|
120
|
+
* @param {*} res
|
|
121
|
+
* @param {*} download
|
|
122
|
+
*/
|
|
123
|
+
serveObject: function (file, res, download) {
|
|
124
|
+
if (file.s3_store) {
|
|
125
|
+
var s3 = createS3Client();
|
|
126
|
+
const bucket = getState().getConfig("storage_s3_bucket");
|
|
127
|
+
|
|
128
|
+
var params = {
|
|
129
|
+
Bucket: bucket,
|
|
130
|
+
Key: file.location,
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
// Forward the object
|
|
134
|
+
s3.getObject(params)
|
|
135
|
+
.on("httpHeaders", function (statusCode, headers) {
|
|
136
|
+
if (!!download)
|
|
137
|
+
res.set("Content-Disposition", contentDisposition(file.filename));
|
|
138
|
+
res.set("Content-Length", headers["content-length"]);
|
|
139
|
+
this.response.httpResponse.createUnbufferedStream().pipe(res);
|
|
140
|
+
})
|
|
141
|
+
.send();
|
|
142
|
+
} else {
|
|
143
|
+
// Use legacy file download
|
|
144
|
+
res.download(file.location, file.filename);
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
unlinkObject: function (file) {
|
|
149
|
+
if (file.s3_store) {
|
|
150
|
+
var s3 = createS3Client();
|
|
151
|
+
return new Promise((resolve, reject) => {
|
|
152
|
+
s3.deleteObject(
|
|
153
|
+
{
|
|
154
|
+
Bucket: getState().getConfig("storage_s3_bucket"),
|
|
155
|
+
Key: file.location,
|
|
156
|
+
},
|
|
157
|
+
(err, data) => {
|
|
158
|
+
if (err) reject(err);
|
|
159
|
+
else resolve(data);
|
|
160
|
+
}
|
|
161
|
+
);
|
|
162
|
+
});
|
|
163
|
+
} else {
|
|
164
|
+
return fs.unlink(file.location);
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
};
|