@saltcorn/server 0.9.1-beta.0 → 0.9.1-beta.10

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/routes/fields.js CHANGED
@@ -996,6 +996,30 @@ router.post(
996
996
  result = row[field.name];
997
997
  } else if (field.stored) {
998
998
  const f = get_async_expression_function(formula, fields);
999
+ //are there join fields in formula?
1000
+ const joinFields = {};
1001
+ add_free_variables_to_joinfields(
1002
+ freeVariables(formula),
1003
+ joinFields,
1004
+ table.fields
1005
+ );
1006
+ for (const { target, ref, through, rename_object } of Object.values(
1007
+ joinFields
1008
+ )) {
1009
+ const jf = table.getField(ref);
1010
+ const jtable = Table.findOne(jf.reftable_name);
1011
+ const jrow = await jtable.getRow({ [jtable.pk_name]: row[ref] });
1012
+ row[ref] = jrow;
1013
+ if (through) {
1014
+ const jf2 = jtable.getField(through);
1015
+ const jtable2 = Table.findOne(jf2.reftable_name);
1016
+ const jrow2 = await jtable2.getRow({
1017
+ [jtable2.pk_name]: jrow[through],
1018
+ });
1019
+ row[ref][through] = jrow2;
1020
+ }
1021
+ }
1022
+
999
1023
  result = await f(row);
1000
1024
  } else {
1001
1025
  const f = get_expression_function(formula, fields);
@@ -1145,7 +1169,10 @@ router.post(
1145
1169
  }
1146
1170
 
1147
1171
  const field = table.getField(fieldName);
1148
-
1172
+ if (!field) {
1173
+ res.send("");
1174
+ return;
1175
+ }
1149
1176
  const fieldViewConfigForms = await calcfldViewConfig([field], false, 0);
1150
1177
  const formFields = fieldViewConfigForms[field.name][fv_name];
1151
1178
  if (!formFields) {
@@ -12,8 +12,9 @@ const View = require("@saltcorn/data/models/view");
12
12
  const User = require("@saltcorn/data/models/user");
13
13
  const File = require("@saltcorn/data/models/file");
14
14
  const Page = require("@saltcorn/data/models/page");
15
+ const Plugin = require("@saltcorn/data/models/plugin");
15
16
  const { link, mkTable } = require("@saltcorn/markup");
16
- const { div, a, p, i } = require("@saltcorn/markup/tags");
17
+ const { div, a, p, i, h5, span } = require("@saltcorn/markup/tags");
17
18
  const Table = require("@saltcorn/data/models/table");
18
19
  const { get_cached_packs } = require("@saltcorn/admin-models/models/pack");
19
20
  // const { restore_backup } = require("../markup/admin");
@@ -21,7 +22,7 @@ const { get_latest_npm_version } = require("@saltcorn/data/models/config");
21
22
  const packagejson = require("../package.json");
22
23
  const Trigger = require("@saltcorn/data/models/trigger");
23
24
  const { fileUploadForm } = require("../markup/forms");
24
- const { get_base_url } = require("./utils.js");
25
+ const { get_base_url, sendHtmlFile } = require("./utils.js");
25
26
 
26
27
  /**
27
28
  * Tables List
@@ -310,10 +311,80 @@ const packTab = (req, packlist) =>
310
311
  { noHeader: true }
311
312
  ),
312
313
  a(
313
- { href: `/plugins?set=packs`, class: "btn btn-primary" },
314
+ { href: `/plugins?set=packs`, class: "btn btn-sm btn-primary" },
314
315
  req.__("Go to pack store »")
315
316
  )
316
317
  );
318
+
319
+ const themeCard = (req, roleMap) => {
320
+ const state_layouts = getState().layouts;
321
+ const state_layout_names = Object.keys(state_layouts);
322
+ const layout_by_role = getState().getConfig("layout_by_role");
323
+ const used_layout_by_role = {};
324
+ Object.keys(roleMap).forEach((role_id) => {
325
+ used_layout_by_role[role_id] =
326
+ layout_by_role[role_id] ||
327
+ state_layout_names[state_layout_names.length - 1];
328
+ });
329
+ const themes_available = Plugin.get_cached_plugins().filter(
330
+ (p) => p.has_theme && !state_layout_names.includes(p.name)
331
+ );
332
+ const layouts = Object.entries(getState().layouts)
333
+ .filter(([nm, v]) => nm !== "emergency")
334
+ .map(([name, layout]) => {
335
+ let plugin = getState().plugins[name];
336
+ const for_role = Object.entries(used_layout_by_role)
337
+ .filter(([role, rname]) => rname === name)
338
+ .map(([role, rname]) =>
339
+ span({ class: "badge bg-info" }, roleMap[role])
340
+ );
341
+
342
+ return {
343
+ name,
344
+ layout,
345
+ plugin,
346
+ for_role,
347
+ edit_cfg_link: plugin?.configuration_workflow
348
+ ? a(
349
+ {
350
+ href: `/plugins/configure/${encodeURIComponent(name)}`,
351
+ },
352
+ i({ class: "fa fa-cog ms-2" })
353
+ )
354
+ : "",
355
+ };
356
+ });
357
+ const show_installable = themes_available.length > 0 || layouts.length == 1;
358
+ return div(
359
+ { class: "pb-3 pt-2 pe-4" },
360
+ mkTable(
361
+ [
362
+ {
363
+ label: req.__("Installed theme"),
364
+ key: ({ name, edit_cfg_link }) => `${name}${edit_cfg_link}`,
365
+ },
366
+ {
367
+ label: req.__("Theme for role"),
368
+ key: ({ for_role }) => for_role.join(" "),
369
+ },
370
+ ],
371
+ layouts
372
+ ),
373
+ a({ href: "/roleadmin" }, req.__("Set theme for each user role »")),
374
+ show_installable && h5({ class: "mt-2" }, req.__("Available themes")),
375
+ show_installable &&
376
+ div(
377
+ themes_available
378
+ .map((p) => span({ class: "badge bg-secondary" }, p.name))
379
+ .join(" ")
380
+ ),
381
+ show_installable &&
382
+ a(
383
+ { href: `/plugins?set=themes`, class: "mt-2" },
384
+ req.__("Install more themes »")
385
+ )
386
+ );
387
+ };
317
388
  /**
318
389
  * Help Card
319
390
  * @param req
@@ -412,10 +483,12 @@ const welcome_page = async (req) => {
412
483
  users.length > 4
413
484
  ? {
414
485
  Users: await usersTab(req, users, roleMap),
486
+ Theme: themeCard(req, roleMap),
415
487
  Help: helpCard(req),
416
488
  }
417
489
  : {
418
490
  Help: helpCard(req),
491
+ Theme: themeCard(req, roleMap),
419
492
  Users: await usersTab(req, users, roleMap),
420
493
  },
421
494
  },
@@ -480,15 +553,16 @@ const get_config_response = async (role_id, res, req) => {
480
553
 
481
554
  if (db_page) {
482
555
  const contents = await db_page.run(req.query, { res, req });
483
-
484
- res.sendWrap(
485
- {
486
- title: db_page.title,
487
- description: db_page.description,
488
- bodyClass: "page_" + db.sqlsanitize(homeCfg),
489
- },
490
- contents
491
- );
556
+ if (contents.html_file) await sendHtmlFile(req, res, contents.html_file);
557
+ else
558
+ res.sendWrap(
559
+ {
560
+ title: db_page.title,
561
+ description: db_page.description,
562
+ bodyClass: "page_" + db.sqlsanitize(homeCfg),
563
+ },
564
+ contents
565
+ );
492
566
  } else res.redirect(homeCfg);
493
567
  return true;
494
568
  }
package/routes/page.js CHANGED
@@ -8,12 +8,15 @@ const Router = require("express-promise-router");
8
8
 
9
9
  const Page = require("@saltcorn/data/models/page");
10
10
  const Trigger = require("@saltcorn/data/models/trigger");
11
+ const File = require("@saltcorn/data/models/file");
11
12
  const { getState } = require("@saltcorn/data/db/state");
12
13
  const {
13
14
  error_catcher,
14
15
  scan_for_page_title,
15
16
  isAdmin,
17
+ sendHtmlFile,
16
18
  } = require("../routes/utils.js");
19
+ const { isTest } = require("@saltcorn/data/utils");
17
20
  const { add_edit_bar } = require("../markup/admin.js");
18
21
  const { traverseSync } = require("@saltcorn/data/models/layout");
19
22
  const { run_action_column } = require("@saltcorn/data/plugin-helper");
@@ -50,27 +53,30 @@ router.get(
50
53
  const title = scan_for_page_title(contents, db_page.title);
51
54
  const tock = new Date();
52
55
  const ms = tock.getTime() - tic.getTime();
53
- Trigger.emitEvent("PageLoad", null, req.user, {
54
- text: req.__("Page '%s' was loaded", pagename),
55
- type: "page",
56
- name: pagename,
57
- render_time: ms,
58
- });
59
- res.sendWrap(
60
- {
61
- title,
62
- description: db_page.description,
63
- bodyClass: "page_" + db.sqlsanitize(pagename),
64
- no_menu: db_page.attributes?.no_menu,
65
- } || `${pagename} page`,
66
- add_edit_bar({
67
- role,
68
- title: db_page.name,
69
- what: req.__("Page"),
70
- url: `/pageedit/edit/${encodeURIComponent(db_page.name)}`,
71
- contents,
72
- })
73
- );
56
+ if (!isTest())
57
+ Trigger.emitEvent("PageLoad", null, req.user, {
58
+ text: req.__("Page '%s' was loaded", pagename),
59
+ type: "page",
60
+ name: pagename,
61
+ render_time: ms,
62
+ });
63
+ if (contents.html_file) await sendHtmlFile(req, res, contents.html_file);
64
+ else
65
+ res.sendWrap(
66
+ {
67
+ title,
68
+ description: db_page.description,
69
+ bodyClass: "page_" + db.sqlsanitize(pagename),
70
+ no_menu: db_page.attributes?.no_menu,
71
+ } || `${pagename} page`,
72
+ add_edit_bar({
73
+ role,
74
+ title: db_page.name,
75
+ what: req.__("Page"),
76
+ url: `/pageedit/edit/${encodeURIComponent(db_page.name)}`,
77
+ contents,
78
+ })
79
+ );
74
80
  } else {
75
81
  if (db_page && !req.user) {
76
82
  res.redirect(`/auth/login?dest=${encodeURIComponent(req.originalUrl)}`);
@@ -9,7 +9,7 @@ const View = require("@saltcorn/data/models/view");
9
9
  const Field = require("@saltcorn/data/models/field");
10
10
  const Table = require("@saltcorn/data/models/table");
11
11
  const Page = require("@saltcorn/data/models/page");
12
- const { div, a } = require("@saltcorn/markup/tags");
12
+ const { div, a, iframe, script } = require("@saltcorn/markup/tags");
13
13
  const { getState } = require("@saltcorn/data/db/state");
14
14
  const User = require("@saltcorn/data/models/user");
15
15
  const Workflow = require("@saltcorn/data/models/workflow");
@@ -27,6 +27,7 @@ const {
27
27
  addOnDoneRedirect,
28
28
  is_relative_url,
29
29
  } = require("./utils.js");
30
+ const { asyncMap } = require("@saltcorn/data/utils");
30
31
  const {
31
32
  mkTable,
32
33
  renderForm,
@@ -39,6 +40,8 @@ const {
39
40
  } = require("@saltcorn/markup");
40
41
  const { getActionConfigFields } = require("@saltcorn/data/plugin-helper");
41
42
  const Library = require("@saltcorn/data/models/library");
43
+ const path = require("path");
44
+ const fsp = require("fs").promises;
42
45
 
43
46
  /**
44
47
  * @type {object}
@@ -58,6 +61,20 @@ module.exports = router;
58
61
  const pagePropertiesForm = async (req, isNew) => {
59
62
  const roles = await User.get_roles();
60
63
  const pages = (await Page.find()).map((p) => p.name);
64
+ const htmlFiles = await File.find(
65
+ {
66
+ mime_super: "text",
67
+ mime_sub: "html",
68
+ },
69
+ { recursive: true }
70
+ );
71
+ const htmlOptions = await asyncMap(htmlFiles, async (f) => {
72
+ return {
73
+ label: path.join(f.current_folder, f.filename),
74
+ value: File.absPathToServePath(f.location),
75
+ };
76
+ });
77
+
61
78
  const form = new Form({
62
79
  action: addOnDoneRedirect("/pageedit/edit-properties", req),
63
80
  fields: [
@@ -92,6 +109,24 @@ const pagePropertiesForm = async (req, isNew) => {
92
109
  input_type: "select",
93
110
  options: roles.map((r) => ({ value: r.id, label: r.role })),
94
111
  },
112
+ ...(htmlOptions.length > 0
113
+ ? [
114
+ {
115
+ name: "html_file",
116
+ label: req.__("HTML file"),
117
+ sublabel: req.__("HTML file to use as page content"),
118
+ input_type: "select",
119
+
120
+ options: [
121
+ {
122
+ label: req.__("None - use drag and drop builder"),
123
+ value: "",
124
+ },
125
+ ...htmlOptions,
126
+ ],
127
+ },
128
+ ]
129
+ : []),
95
130
  {
96
131
  name: "no_menu",
97
132
  label: req.__("No menu"),
@@ -367,23 +402,146 @@ router.post(
367
402
  wrap(renderForm(form, req.csrfToken()), false, req)
368
403
  );
369
404
  } else {
370
- const { id, columns, no_menu, ...pageRow } = form.values;
405
+ const { id, columns, no_menu, html_file, ...pageRow } = form.values;
371
406
  pageRow.min_role = +pageRow.min_role;
372
407
  pageRow.attributes = { no_menu };
408
+ if (html_file) {
409
+ pageRow.layout = {
410
+ html_file: html_file,
411
+ };
412
+ }
373
413
  if (+id) {
414
+ const dbPage = Page.findOne({ id: id });
415
+ if (dbPage.layout?.html_file && !html_file) {
416
+ pageRow.layout = {};
417
+ }
374
418
  await Page.update(+id, pageRow);
375
419
  res.redirect(`/pageedit/`);
376
420
  } else {
377
- if (!pageRow.fixed_states) pageRow.fixed_states = {};
378
421
  if (!pageRow.layout) pageRow.layout = {};
422
+ if (!pageRow.fixed_states) pageRow.fixed_states = {};
379
423
  await Page.create(pageRow);
380
- res.redirect(addOnDoneRedirect(`/pageedit/edit/${pageRow.name}`, req));
424
+ if (!html_file)
425
+ res.redirect(
426
+ addOnDoneRedirect(`/pageedit/edit/${pageRow.name}`, req)
427
+ );
428
+ else res.redirect(`/pageedit/`);
381
429
  }
382
430
  }
383
431
  })
384
432
  );
385
433
 
386
434
  /**
435
+ * open the builder
436
+ * @param {*} req
437
+ * @param {*} res
438
+ * @param {*} page
439
+ */
440
+ const getEditNormalPage = async (req, res, page) => {
441
+ // set fixed states in page directly for legacy builds
442
+ traverseSync(page.layout, {
443
+ view(s) {
444
+ if (s.state === "fixed" && !s.configuration) {
445
+ const fs = page.fixed_states[s.name];
446
+ if (fs) s.configuration = fs;
447
+ }
448
+ },
449
+ });
450
+ const options = await pageBuilderData(req, page);
451
+ const builderData = {
452
+ options,
453
+ context: page,
454
+ layout: page.layout,
455
+ mode: "page",
456
+ version_tag: db.connectObj.version_tag,
457
+ };
458
+ res.sendWrap(
459
+ req.__(`%s configuration`, page.name),
460
+ wrap(renderBuilder(builderData, req.csrfToken()), true, req, page)
461
+ );
462
+ };
463
+
464
+ /**
465
+ * open a file editor with an iframe preview
466
+ * @param {*} req
467
+ * @param {*} res
468
+ * @param {*} page
469
+ */
470
+ const getEditPageWithHtmlFile = async (req, res, page) => {
471
+ const htmlFile = page.html_file;
472
+ const iframeId = "page_preview_iframe";
473
+ const updateBttnId = "addnUpdBtn";
474
+ const file = await File.findOne(htmlFile);
475
+ if (!file) {
476
+ req.flash("error", req.__("File not found"));
477
+ return res.redirect(`/pageedit`);
478
+ }
479
+ const editForm = new Form({
480
+ action: `/pageedit/edit/${encodeURIComponent(page.name)}`,
481
+ fields: [
482
+ {
483
+ name: "code",
484
+ form_name: "code",
485
+ label: "Code",
486
+ input_type: "code",
487
+ attributes: { mode: "text/html" },
488
+ validator(s) {
489
+ return true;
490
+ },
491
+ },
492
+ ],
493
+ values: {
494
+ code: await fsp.readFile(file.location, "utf8"),
495
+ },
496
+ onChange: `document.getElementById('${updateBttnId}').disabled = false;`,
497
+ additionalButtons: [
498
+ {
499
+ label: req.__("Update"),
500
+ id: updateBttnId,
501
+ class: "btn btn-primary",
502
+ onclick: `saveAndContinue(this, () => {
503
+ document.getElementById('${iframeId}').contentWindow.location.reload();
504
+ document.getElementById('${updateBttnId}').disabled = true;
505
+ })`,
506
+ disabled: true,
507
+ },
508
+ ],
509
+ submitLabel: req.__("Finish") + " »",
510
+ });
511
+ res.sendWrap(req.__("Edit %s", page.title), {
512
+ above: [
513
+ {
514
+ type: "card",
515
+ title: "Edit",
516
+ titleAjaxIndicator: true,
517
+ contents: [renderForm(editForm, req.csrfToken())],
518
+ },
519
+ {
520
+ type: "card",
521
+ title: "Preview",
522
+ contents: [
523
+ iframe({
524
+ id: iframeId,
525
+ src: `/files/serve/${encodeURIComponent(htmlFile)}`,
526
+ }),
527
+ script(`
528
+ const iframe = document.getElementById("${iframeId}");
529
+ iframe.onload = () => {
530
+ const _iframe = document.getElementById("${iframeId}");
531
+ if (_iframe.contentWindow.document.body) {
532
+ _iframe.width = _iframe.contentWindow.document.body.scrollWidth;
533
+ _iframe.height = _iframe.contentWindow.document.body.scrollHeight;
534
+ }
535
+ }`),
536
+ ],
537
+ },
538
+ ],
539
+ });
540
+ };
541
+
542
+ /**
543
+ * for normal pages, open the builder
544
+ * for pages with a fixed html file, open a file editor with an iframe preview
387
545
  * @name get/edit/:pagename
388
546
  * @function
389
547
  * @memberof module:routes/pageedit~pageeditRouter
@@ -399,27 +557,8 @@ router.get(
399
557
  req.flash("error", req.__(`Page %s not found`, pagename));
400
558
  res.redirect(`/pageedit`);
401
559
  } else {
402
- // set fixed states in page directly for legacy builds
403
- traverseSync(page.layout, {
404
- view(s) {
405
- if (s.state === "fixed" && !s.configuration) {
406
- const fs = page.fixed_states[s.name];
407
- if (fs) s.configuration = fs;
408
- }
409
- },
410
- });
411
- const options = await pageBuilderData(req, page);
412
- const builderData = {
413
- options,
414
- context: page,
415
- layout: page.layout,
416
- mode: "page",
417
- version_tag: db.connectObj.version_tag,
418
- };
419
- res.sendWrap(
420
- req.__(`%s configuration`, page.name),
421
- wrap(renderBuilder(builderData, req.csrfToken()), true, req, page)
422
- );
560
+ if (!page.html_file) await getEditNormalPage(req, res, page);
561
+ else await getEditPageWithHtmlFile(req, res, page);
423
562
  }
424
563
  })
425
564
  );
@@ -448,13 +587,33 @@ router.post(
448
587
  await Page.update(page.id, {
449
588
  layout: decodeURIComponent(req.body.layout),
450
589
  });
451
-
452
590
  req.flash("success", req.__(`Page %s saved`, pagename));
453
591
  res.redirect(redirectTarget);
592
+ } else if (req.body.code) {
593
+ try {
594
+ if (!page.html_file) throw new Error(req.__("File not found"));
595
+ const file = await File.findOne(page.html_file);
596
+ if (!file) throw new Error(req.__("File not found"));
597
+ await fsp.writeFile(file.location, req.body.code);
598
+ if (!req.xhr) {
599
+ req.flash("success", req.__(`Page %s saved`, pagename));
600
+ res.redirect(redirectTarget);
601
+ } else res.json({ okay: true });
602
+ } catch (error) {
603
+ getState().log(2, `POST /edit/${pagename}: '${error.message}'`);
604
+ req.flash(
605
+ "error",
606
+ `${req.__("Error")}: ${error.message || req.__("An error occurred")}`
607
+ );
608
+ if (!req.xhr) res.redirect(redirectTarget);
609
+ else res.json({ error: error.message });
610
+ }
454
611
  } else {
612
+ getState().log(2, `POST /edit/${pagename}: '${req.body}'`);
455
613
  req.flash("error", req.__(`Error processing page`));
456
614
  res.redirect(redirectTarget);
457
615
  }
616
+ getState().log(5, `POST /edit/${pagename}: Success`);
458
617
  })
459
618
  );
460
619
 
package/routes/utils.js CHANGED
@@ -18,6 +18,7 @@ const cookieSession = require("cookie-session");
18
18
  const is = require("contractis/is");
19
19
  const { validateHeaderName, validateHeaderValue } = require("http");
20
20
  const Crash = require("@saltcorn/data/models/crash");
21
+ const File = require("@saltcorn/data/models/file");
21
22
  const si = require("systeminformation");
22
23
  const {
23
24
  config_fields_form,
@@ -25,6 +26,8 @@ const {
25
26
  check_if_restart_required,
26
27
  flash_restart,
27
28
  } = require("../markup/admin.js");
29
+ const path = require("path");
30
+
28
31
  const get_sys_info = async () => {
29
32
  const disks = await si.fsSize();
30
33
  let size = 0;
@@ -380,6 +383,38 @@ const admin_config_route = ({
380
383
  );
381
384
  };
382
385
 
386
+ /**
387
+ * Send HTML file to client without any menu
388
+ * @param {any} req
389
+ * @param {any} res
390
+ * @param {string} file
391
+ * @returns
392
+ */
393
+ const sendHtmlFile = async (req, res, file) => {
394
+ const fullPath = path.join((await File.rootFolder()).location, file);
395
+ const role = req.user && req.user.id ? req.user.role_id : 100;
396
+ try {
397
+ const scFile = await File.from_file_on_disk(
398
+ path.basename(fullPath),
399
+ path.dirname(fullPath)
400
+ );
401
+ if (scFile && role <= scFile.min_role_read) {
402
+ res.sendFile(fullPath);
403
+ } else {
404
+ return res
405
+ .status(404)
406
+ .sendWrap(req.__("An error occurred"), req.__("File not found"));
407
+ }
408
+ } catch (e) {
409
+ return res
410
+ .status(404)
411
+ .sendWrap(
412
+ req.__("An error occurred"),
413
+ e.message || req.__("An error occurred")
414
+ );
415
+ }
416
+ };
417
+
383
418
  module.exports = {
384
419
  sqlsanitize,
385
420
  csrfField,
@@ -396,4 +431,5 @@ module.exports = {
396
431
  is_relative_url,
397
432
  get_sys_info,
398
433
  admin_config_route,
434
+ sendHtmlFile,
399
435
  };
package/routes/view.js CHANGED
@@ -18,7 +18,7 @@ const {
18
18
  setTenant,
19
19
  } = require("../routes/utils.js");
20
20
  const { add_edit_bar } = require("../markup/admin.js");
21
- const { InvalidConfiguration } = require("@saltcorn/data/utils");
21
+ const { InvalidConfiguration, isTest } = require("@saltcorn/data/utils");
22
22
  const { getState } = require("@saltcorn/data/db/state");
23
23
 
24
24
  /**
@@ -88,12 +88,13 @@ router.get(
88
88
  res.set("SaltcornModalLinkOut", `true`);
89
89
  const tock = new Date();
90
90
  const ms = tock.getTime() - tic.getTime();
91
- Trigger.emitEvent("PageLoad", null, req.user, {
92
- text: req.__("View '%s' was loaded", viewname),
93
- type: "view",
94
- name: viewname,
95
- render_time: ms,
96
- });
91
+ if (!isTest())
92
+ Trigger.emitEvent("PageLoad", null, req.user, {
93
+ text: req.__("View '%s' was loaded", viewname),
94
+ type: "view",
95
+ name: viewname,
96
+ render_time: ms,
97
+ });
97
98
  if (typeof contents === "object" && contents.goto)
98
99
  res.redirect(contents.goto);
99
100
  else
package/s3storage.js CHANGED
@@ -1,5 +1,4 @@
1
- require("aws-sdk/lib/maintenance_mode_message").suppress = true;
2
- const aws = require("aws-sdk");
1
+ const { S3 } = require("@aws-sdk/client-s3");
3
2
  const multer = require("multer");
4
3
  const multerS3 = require("multer-s3");
5
4
  const { getState } = require("@saltcorn/data/db/state");
@@ -8,9 +7,11 @@ const { v4: uuidv4 } = require("uuid");
8
7
  const contentDisposition = require("content-disposition");
9
8
  const fs = require("fs");
10
9
  function createS3Client() {
11
- return new aws.S3({
12
- secretAccessKey: getState().getConfig("storage_s3_access_secret"),
13
- accessKeyId: getState().getConfig("storage_s3_access_key"),
10
+ return new S3({
11
+ credentials: {
12
+ secretAccessKey: getState().getConfig("storage_s3_access_secret"),
13
+ accessKeyId: getState().getConfig("storage_s3_access_key"),
14
+ },
14
15
  region: getState().getConfig("storage_s3_region"),
15
16
  endpoint: getState().getConfig("storage_s3_endpoint"),
16
17
  });