@saltcorn/server 0.7.1 → 0.7.2-beta.0

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/locales/en.json CHANGED
@@ -888,5 +888,6 @@
888
888
  "Cannot install unsafe plugins on subdomain tenants": "Cannot install unsafe plugins on subdomain tenants",
889
889
  "Default order descending?": "Default order descending?",
890
890
  "This is the view to which the user will be sent when the form is submitted. The view you specify here can be ignored depending on the context of the form, for instance if it appears in a pop-up the redirect will not take place.": "This is the view to which the user will be sent when the form is submitted. The view you specify here can be ignored depending on the context of the form, for instance if it appears in a pop-up the redirect will not take place.",
891
- "Destination view": "Destination view"
891
+ "Destination view": "Destination view",
892
+ "Finish": "Finish"
892
893
  }
package/package.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "@saltcorn/server",
3
- "version": "0.7.1",
3
+ "version": "0.7.2-beta.0",
4
4
  "description": "Server app for Saltcorn, open-source no-code platform",
5
5
  "homepage": "https://saltcorn.com",
6
6
  "main": "index.js",
7
7
  "license": "MIT",
8
8
  "dependencies": {
9
- "@saltcorn/base-plugin": "0.7.1",
10
- "@saltcorn/builder": "0.7.1",
11
- "@saltcorn/data": "0.7.1",
12
- "@saltcorn/admin-models": "0.7.1",
13
- "@saltcorn/markup": "0.7.1",
14
- "@saltcorn/sbadmin2": "0.7.1",
9
+ "@saltcorn/base-plugin": "0.7.2-beta.0",
10
+ "@saltcorn/builder": "0.7.2-beta.0",
11
+ "@saltcorn/data": "0.7.2-beta.0",
12
+ "@saltcorn/admin-models": "0.7.2-beta.0",
13
+ "@saltcorn/markup": "0.7.2-beta.0",
14
+ "@saltcorn/sbadmin2": "0.7.2-beta.0",
15
15
  "@socket.io/cluster-adapter": "^0.1.0",
16
16
  "@socket.io/sticky": "^1.0.1",
17
17
  "aws-sdk": "^2.1037.0",
@@ -46,6 +46,7 @@
46
46
  "pg": "^8.2.1",
47
47
  "pluralize": "^8.0.0",
48
48
  "qrcode": "1.5.0",
49
+ "sharp": "0.30.3",
49
50
  "socket.io": "4.2.0",
50
51
  "thirty-two": "1.0.2",
51
52
  "tmp-promise": "^3.0.2",
@@ -58,6 +59,7 @@
58
59
  "repository": "github:saltcorn/saltcorn",
59
60
  "devDependencies": {
60
61
  "jest": "26.6.3",
62
+ "jest-environment-jsdom": "^26.6.2",
61
63
  "supertest": "^4.0.2"
62
64
  },
63
65
  "scripts": {
@@ -117,6 +117,7 @@ function MenuEditor(e, t) {
117
117
  (n.prev("div").children(".sortableListsOpener").first().remove(),
118
118
  n.remove()),
119
119
  MenuEditor.updateButtons(s);
120
+ l.onUpdate();
120
121
  }
121
122
  }),
122
123
  $(document).on("click", ".btnEdit", function (e) {
@@ -145,11 +146,13 @@ function MenuEditor(e, t) {
145
146
  e.preventDefault();
146
147
  var t = $(this).closest("li");
147
148
  t.prev("li").before(t), MenuEditor.updateButtons(s);
149
+ l.onUpdate();
148
150
  }),
149
151
  s.on("click", ".btnDown", function (e) {
150
152
  e.preventDefault();
151
153
  var t = $(this).closest("li");
152
154
  t.next("li").after(t), MenuEditor.updateButtons(s);
155
+ l.onUpdate();
153
156
  }),
154
157
  s.on("click", ".btnOut", function (e) {
155
158
  e.preventDefault();
@@ -161,6 +164,7 @@ function MenuEditor(e, t) {
161
164
  t.remove()),
162
165
  MenuEditor.updateButtons(s),
163
166
  s.updateLevels();
167
+ l.onUpdate();
164
168
  }),
165
169
  s.on("click", ".btnIn", function (e) {
166
170
  e.preventDefault();
@@ -174,6 +178,7 @@ function MenuEditor(e, t) {
174
178
  l.append(n), n.append(t), l.addClass("sortableListsOpen"), f(l);
175
179
  }
176
180
  MenuEditor.updateButtons(s), s.updateLevels();
181
+ l.onUpdate();
177
182
  }),
178
183
  (this.setForm = function (e) {
179
184
  i = e;
@@ -224,3 +224,12 @@ footer.bs-mobile-nav-footer {
224
224
  .form-group {
225
225
  margin-bottom: 1rem;
226
226
  }
227
+
228
+ .containerbgimage {
229
+ position: absolute;
230
+ top: 0;
231
+ left: 0;
232
+ width: 100%;
233
+ height: 100%;
234
+ z-index: -1;
235
+ }
@@ -618,6 +618,47 @@ function saveAndContinue(e, k) {
618
618
  return false;
619
619
  }
620
620
 
621
+ function applyViewConfig(e, url) {
622
+ var form = $(e).closest("form");
623
+ var form_data = form.serializeArray();
624
+ const cfg = {};
625
+ form_data.forEach((item) => {
626
+ cfg[item.name] = item.value;
627
+ });
628
+ $.ajax(url, {
629
+ type: "POST",
630
+ dataType: "json",
631
+ contentType: "application/json",
632
+ headers: {
633
+ "CSRF-Token": _sc_globalCsrf,
634
+ },
635
+ data: JSON.stringify(cfg),
636
+ error: function (request) {},
637
+ });
638
+
639
+ return false;
640
+ }
641
+
642
+ const repeaterCopyValuesToForm = (form, editor) => {
643
+ const vs = JSON.parse(editor.getString());
644
+ //console.log(vs)
645
+ const setVal = (k, ix, v) => {
646
+ const $e = form.find(`input[name="${k}_${ix}"]`);
647
+ if ($e.length) $e.val(v);
648
+ else
649
+ form.append(
650
+ `<input type="hidden" name="${k}_${ix}" value="${v}"></input>`
651
+ );
652
+ };
653
+ vs.forEach((v, ix) => {
654
+ Object.entries(v).forEach(([k, v]) => {
655
+ //console.log(ix, k, typeof v, v)
656
+ if (typeof v === "boolean") setVal(k, ix, v ? "on" : "");
657
+ else setVal(k, ix, v);
658
+ });
659
+ });
660
+ };
661
+
621
662
  function ajaxSubmitForm(e) {
622
663
  var form = $(e).closest("form");
623
664
  var url = form.attr("action");
@@ -834,7 +875,7 @@ const columnSummary = (col) => {
834
875
  if (!col) return "Unknown";
835
876
  switch (col.type) {
836
877
  case "Field":
837
- return `Field ${col.field_name} ${col.fieldview}`;
878
+ return `Field ${col.field_name} ${col.fieldview || ""}`;
838
879
  case "Link":
839
880
  return `Link ${col.link_text}`;
840
881
  case "JoinField":
package/routes/files.js CHANGED
@@ -9,6 +9,7 @@ const File = require("@saltcorn/data/models/file");
9
9
  const User = require("@saltcorn/data/models/user");
10
10
  const { getState } = require("@saltcorn/data/db/state");
11
11
  const s3storage = require("../s3storage");
12
+ const sharp = require("sharp");
12
13
 
13
14
  const {
14
15
  mkTable,
@@ -43,6 +44,8 @@ const {
43
44
  config_fields_form,
44
45
  save_config_from_form,
45
46
  } = require("../markup/admin");
47
+ const fsp = require("fs").promises;
48
+ const fs = require("fs");
46
49
 
47
50
  /**
48
51
  * @type {object}
@@ -187,6 +190,54 @@ router.get(
187
190
  })
188
191
  );
189
192
 
193
+ /**
194
+ * @name get/resize/:id
195
+ * @function
196
+ * @memberof module:routes/files~filesRouter
197
+ * @function
198
+ */
199
+ router.get(
200
+ "/resize/:id/:width_str",
201
+ error_catcher(async (req, res) => {
202
+ const role = req.user && req.user.id ? req.user.role_id : 10;
203
+ const user_id = req.user && req.user.id;
204
+ const { id, width_str } = req.params;
205
+ let file;
206
+ if (typeof strictParseInt(id) !== "undefined")
207
+ file = await File.findOne({ id });
208
+ else file = await File.findOne({ filename: id });
209
+
210
+ if (!file) {
211
+ res
212
+ .status(404)
213
+ .sendWrap(req.__("Not found"), h1(req.__("File not found")));
214
+ return;
215
+ }
216
+ if (role <= file.min_role_read || (user_id && user_id === file.user_id)) {
217
+ res.type(file.mimetype);
218
+ const cacheability = file.min_role_read === 10 ? "public" : "private";
219
+ res.set("Cache-Control", `${cacheability}, max-age=86400`);
220
+ //TODO s3
221
+ if (file.s3_store) s3storage.serveObject(file, res, false);
222
+ else {
223
+ const width = strictParseInt(width_str);
224
+ if (!width) {
225
+ res.sendFile(file.location);
226
+ return;
227
+ }
228
+ const fnm = `${file.location}_w${width}`;
229
+ if (!fs.existsSync(fnm)) {
230
+ await sharp(file.location).resize({ width }).toFile(fnm);
231
+ }
232
+ res.sendFile(fnm);
233
+ }
234
+ } else {
235
+ req.flash("warning", req.__("Not authorized"));
236
+ res.redirect("/");
237
+ }
238
+ })
239
+ );
240
+
190
241
  /**
191
242
  * @name post/setrole/:id
192
243
  * @function
@@ -582,8 +582,11 @@ router.get(
582
582
  return;
583
583
  }
584
584
  const configFlow = await view.get_config_flow(req);
585
+ const hasConfig =
586
+ view.configuration && Object.keys(view.configuration).length > 0;
585
587
  const wfres = await configFlow.run(
586
588
  {
589
+ id: hasConfig ? view.id : undefined,
587
590
  table_id: view.table_id,
588
591
  exttable_name: view.exttable_name,
589
592
  viewname: name,
@@ -704,6 +707,48 @@ router.post(
704
707
  })
705
708
  );
706
709
 
710
+ /**
711
+ * @name post/saveconfig/:id
712
+ * @function
713
+ * @memberof module:routes/viewedit~vieweditRouter
714
+ * @function
715
+ */
716
+ router.post(
717
+ "/saveconfig/:viewname",
718
+ isAdmin,
719
+ error_catcher(async (req, res) => {
720
+ const { viewname } = req.params;
721
+
722
+ if (viewname && req.body) {
723
+ const view = await View.findOne({ name: viewname });
724
+ const configFlow = await view.get_config_flow(req);
725
+ const step = await configFlow.singleStepForm(req.body, req);
726
+ if (step?.renderForm) {
727
+ if (!step.renderForm.hasErrors) {
728
+ let newcfg;
729
+ if (step.contextField)
730
+ newcfg = {
731
+ ...view.configuration,
732
+ [step.contextField]: {
733
+ ...view.configuration?.[step.contextField],
734
+ ...step.renderForm.values,
735
+ },
736
+ };
737
+ else newcfg = { ...view.configuration, ...step.renderForm.values };
738
+ await View.update({ configuration: newcfg }, view.id);
739
+ res.json({ success: "ok" });
740
+ } else {
741
+ res.json({ error: step.renderForm.errorSummary });
742
+ }
743
+ } else {
744
+ res.json({ error: "no form" });
745
+ }
746
+ } else {
747
+ res.json({ error: "no view" });
748
+ }
749
+ })
750
+ );
751
+
707
752
  /**
708
753
  * @name post/setrole/:id
709
754
  * @function
@@ -90,7 +90,7 @@ describe("Plugin Endpoints", () => {
90
90
  .expect(toInclude("testfilecontents"));
91
91
  await request(app)
92
92
  .get(
93
- "/plugins/pubdeps/sbadmin2/startbootstrap-sb-admin-2-bs5/4.1.5-beta.0/css/sb-admin-2.min.css"
93
+ "/plugins/pubdeps/sbadmin2/startbootstrap-sb-admin-2-bs5/4.1.5-beta.4/css/sb-admin-2.min.css"
94
94
  )
95
95
  .expect(toInclude("Start Bootstrap"));
96
96
 
@@ -100,7 +100,7 @@ describe("Plugin Endpoints", () => {
100
100
  .expect(toRedirect("/plugins"));
101
101
  await request(app)
102
102
  .get(
103
- "/plugins/pubdeps/sbadmin2/startbootstrap-sb-admin-2-bs5/4.1.5-beta.0/css/sb-admin-2.min.css"
103
+ "/plugins/pubdeps/sbadmin2/startbootstrap-sb-admin-2-bs5/4.1.5-beta.4/css/sb-admin-2.min.css"
104
104
  )
105
105
  .expect(toInclude("Start Bootstrap"));
106
106
  });