@saltcorn/server 0.7.2-beta.3 → 0.7.2-beta.6

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.
@@ -1,365 +1,14 @@
1
- //https://stackoverflow.com/a/698386
2
- jQuery.fn.swapWith = function (to) {
3
- return this.each(function () {
4
- var copy_to = $(to).clone(true);
5
- var copy_from = $(this).clone(true);
6
- $(to).replaceWith(copy_from);
7
- $(this).replaceWith(copy_to);
8
- });
9
- };
10
-
11
- //avoids hiding in overflow:hidden
12
- function init_bs5_dropdowns() {
13
- $("body").on(
14
- "show.bs.dropdown",
15
- "table [data-bs-toggle=dropdown]",
16
- function () {
17
- let target;
18
- if (!$("#page-inner-content").length) target = $("body");
19
- else target = $("#page-inner-content");
20
- let dropdown = bootstrap.Dropdown.getInstance(this);
21
- $(dropdown._menu).insertAfter(target);
22
- }
23
- );
24
- }
25
1
  function sortby(k, desc) {
26
2
  set_state_fields({ _sortby: k, _sortdesc: desc ? "on" : { unset: true } });
27
3
  }
28
4
  function gopage(n, pagesize, extra = {}) {
29
5
  set_state_fields({ ...extra, _page: n, _pagesize: pagesize });
30
6
  }
31
- function add_repeater(nm) {
32
- var es = $("div.form-repeat.repeat-" + nm);
33
- var e = es.first();
34
- var newix = es.length;
35
- var newe = $(e).clone();
36
- newe.find("[name]").each(function (ix, element) {
37
- var newnm = (element.name || "").replace("_0", "_" + newix);
38
- var newid = (element.id || "").replace("_0", "_" + newix);
39
- $(element).attr("name", newnm).attr("id", newid);
40
- });
41
- newe.appendTo($("div.repeats-" + nm));
42
- }
43
- // "e.closest('.form-namespace').find('.coltype').val()==='Field';"
44
- function apply_showif() {
45
- $("[data-show-if]").each(function (ix, element) {
46
- var e = $(element);
47
- try {
48
- var to_show = new Function(
49
- "e",
50
- "return " + decodeURIComponent(e.attr("data-show-if"))
51
- );
52
- if (to_show(e))
53
- e.show()
54
- .find("input, textarea, button, select")
55
- .prop("disabled", e.attr("data-disabled") || false);
56
- else
57
- e.hide().find("input, textarea, button, select").prop("disabled", true);
58
- } catch (e) {
59
- console.error(e);
60
- }
61
- });
62
- $("[data-calc-options]").each(function (ix, element) {
63
- var e = $(element);
64
- var data = JSON.parse(decodeURIComponent(e.attr("data-calc-options")));
65
-
66
- var val = e
67
- .closest(".form-namespace")
68
- .find(`[data-fieldname=${data[0]}]`)
69
- .val();
70
-
71
- var options = data[1][val];
72
- var current = e.attr("data-selected");
73
- //console.log({ val, options, current, data });
74
- e.empty();
75
- (options || []).forEach((o) => {
76
- if (
77
- !(o && typeof o.label !== "undefined" && typeof o.value !== "undefined")
78
- ) {
79
- if (`${current}` === `${o}`)
80
- e.append($("<option selected>" + o + "</option>"));
81
- else e.append($("<option>" + o + "</option>"));
82
- } else {
83
- e.append(
84
- $(
85
- `<option ${
86
- `${current}` === `${o.value}` ? "selected" : ""
87
- } value="${o.value}">${o.label}</option>`
88
- )
89
- );
90
- }
91
- });
92
- e.change(function (ec) {
93
- e.attr("data-selected", ec.target.value);
94
- });
95
- });
96
- $("[data-source-url]").each(function (ix, element) {
97
- const e = $(element);
98
- const rec = get_form_record(e);
99
- ajax_post_json(e.attr("data-source-url"), rec, {
100
- success: (data) => {
101
- e.html(data);
102
- },
103
- error: (err) => {
104
- console.error(err);
105
- e.html("");
106
- },
107
- });
108
- });
109
- }
110
- function get_form_record(e, select_labels) {
111
- const rec = {};
112
- e.closest("form")
113
- .find("input[name],select[name]")
114
- .each(function () {
115
- if (select_labels && $(this).prop("tagName").toLowerCase() === "select")
116
- rec[$(this).attr("name")] = $(this).find("option:selected").text();
117
- else if ($(this).prop("type") === "checkbox")
118
- rec[$(this).attr("name")] = $(this).prop("checked");
119
- else rec[$(this).attr("name")] = $(this).val();
120
- });
121
- return rec;
122
- }
123
- function showIfFormulaInputs(e, fml) {
124
- const rec = get_form_record(e);
125
- return new Function(`{${Object.keys(rec).join(",")}}`, "return " + fml)(rec);
126
- }
127
-
128
- function rep_del(e) {
129
- var myrep = $(e).closest(".form-repeat");
130
- var ix = myrep.index();
131
- var parent = myrep.parent();
132
- parent.children().each(function (childix, element) {
133
- if (childix > ix) {
134
- reindex(element, childix, childix - 1);
135
- }
136
- });
137
- myrep.remove();
138
- }
139
-
140
- function reindex(element, oldix, newix) {
141
- $(element).html(
142
- $(element)
143
- .html()
144
- .split("_" + oldix)
145
- .join("_" + newix)
146
- );
147
- }
148
-
149
- function get_form_subset_record(e) {
150
- const rec = {};
151
- e.find("input[name],select[name]").each(function () {
152
- rec[$(this).attr("name")] = $(this).val();
153
- });
154
- return rec;
155
- }
156
-
157
- function apply_form_subset_record(e, vals) {
158
- e.find("input[name],select[name]").each(function () {
159
- var name = $(this).attr("name");
160
- if (vals[name]) $(this).val(vals[name]);
161
- });
162
- }
163
-
164
- function reindex_form_record(vals, oldix, newix) {
165
- const rec = {};
166
- Object.keys(vals).forEach((k) => {
167
- const newkey = k.split("_" + oldix).join("_" + newix);
168
- rec[newkey] = vals[k];
169
- });
170
- return rec;
171
- }
172
-
173
- function rep_up(e) {
174
- var myrep = $(e).closest(".form-repeat");
175
- var theform = $(e).closest("form");
176
- var ix = myrep.index();
177
- var parent = myrep.parent();
178
- if (ix > 0) {
179
- var swap_with = parent.children(".form-repeat").eq(ix - 1);
180
- var vals1 = reindex_form_record(get_form_subset_record(myrep), ix, ix - 1);
181
- var vals2 = reindex_form_record(
182
- get_form_subset_record(swap_with),
183
- ix - 1,
184
- ix
185
- );
186
- reindex(myrep, ix, ix - 1);
187
- reindex(swap_with, ix - 1, ix);
188
- $(myrep).swapWith(swap_with);
189
- apply_form_subset_record(theform, vals2);
190
- apply_form_subset_record(theform, vals1);
191
- }
192
- }
193
-
194
- function rep_down(e) {
195
- var myrep = $(e).closest(".form-repeat");
196
- var theform = $(e).closest("form");
197
- var ix = myrep.index();
198
- var parent = myrep.parent();
199
- var nchildren = parent.children(".form-repeat").length;
200
- if (ix < nchildren - 1) {
201
- var swap_with = parent.children(".form-repeat").eq(ix + 1);
202
- var vals1 = reindex_form_record(get_form_subset_record(myrep), ix, ix + 1);
203
- var vals2 = reindex_form_record(
204
- get_form_subset_record(swap_with),
205
- ix + 1,
206
- ix
207
- );
208
- reindex(myrep, ix, ix + 1);
209
- reindex(swap_with, ix + 1, ix);
210
- $(myrep).swapWith(swap_with);
211
- apply_form_subset_record(theform, vals2);
212
- apply_form_subset_record(theform, vals1);
213
- }
214
- }
215
7
 
216
- function reload_on_init() {
217
- localStorage.setItem("reload_on_init", true);
218
- }
219
8
  if (localStorage.getItem("reload_on_init")) {
220
9
  localStorage.removeItem("reload_on_init");
221
10
  location.reload();
222
11
  }
223
- function initialize_page() {
224
- $(".blur-on-enter-keypress").bind("keyup", function (e) {
225
- if (e.keyCode === 13) e.target.blur();
226
- });
227
- $("form").change(apply_showif);
228
- apply_showif();
229
- apply_showif();
230
- $("[data-inline-edit-dest-url]").each(function () {
231
- if ($(this).find(".editicon").length === 0) {
232
- var current = $(this).html();
233
- $(this).html(
234
- `<span class="current">${current}</span><i class="editicon fas fa-edit ms-1"></i>`
235
- );
236
- }
237
- });
238
- $("[data-inline-edit-dest-url]").click(function () {
239
- var url = $(this).attr("data-inline-edit-dest-url");
240
- var current = $(this).children("span.current").html();
241
- $(this).replaceWith(
242
- `<form method="post" action="${url}" >
243
- <input type="hidden" name="_csrf" value="${_sc_globalCsrf}">
244
- <input type="text" name="value" value="${current}">
245
- <button type="submit" class="btn btn-sm btn-primary">OK</button>
246
- </form>`
247
- );
248
- });
249
- function setExplainer(that) {
250
- var id = $(that).attr("id") + "_explainer";
251
-
252
- var explainers = JSON.parse(
253
- decodeURIComponent($(that).attr("data-explainers"))
254
- );
255
- var currentVal = explainers[$(that).val()];
256
- $("#" + id).html(`<strong>${$(that).val()}</strong>: ${currentVal}`);
257
- if (currentVal) $("#" + id).show();
258
- else $("#" + id).hide();
259
- }
260
- $("[data-explainers]").each(function () {
261
- var id = $(this).attr("id") + "_explainer";
262
- if ($("#" + id).length === 0) {
263
- $(this).after(`<div class="alert alert-info my-2" id="${id}"></div>`);
264
- setExplainer(this);
265
- }
266
- });
267
- $("[data-explainers]").change(function () {
268
- setExplainer(this);
269
- });
270
-
271
- const codes = [];
272
- $("textarea.to-code").each(function () {
273
- codes.push(this);
274
- });
275
- if (codes.length > 0)
276
- enable_codemirror(() => {
277
- setTimeout(() => {
278
- codes.forEach((el) => {
279
- //console.log($(el).attr("mode"), el);
280
- CodeMirror.fromTextArea(el, {
281
- lineNumbers: true,
282
- mode: $(el).attr("mode"),
283
- });
284
- });
285
- }, 100);
286
- });
287
- const locale =
288
- navigator.userLanguage ||
289
- (navigator.languages &&
290
- navigator.languages.length &&
291
- navigator.languages[0]) ||
292
- navigator.language ||
293
- navigator.browserLanguage ||
294
- navigator.systemLanguage ||
295
- "en";
296
- window.detected_locale = locale;
297
- const parse = (s) => JSON.parse(decodeURIComponent(s));
298
- $("time[locale-time-options]").each(function () {
299
- var el = $(this);
300
- var date = new Date(el.attr("datetime"));
301
- const options = parse(el.attr("locale-time-options"));
302
- el.text(date.toLocaleTimeString(locale, options));
303
- });
304
- $("time[locale-options]").each(function () {
305
- var el = $(this);
306
- var date = new Date(el.attr("datetime"));
307
- const options = parse(el.attr("locale-options"));
308
- el.text(date.toLocaleString(locale, options));
309
- });
310
- $("time[locale-date-options]").each(function () {
311
- var el = $(this);
312
- var date = new Date(el.attr("datetime"));
313
- const options = parse(el.attr("locale-date-options"));
314
- el.text(date.toLocaleDateString(locale, options));
315
- });
316
- $('a[data-bs-toggle="tab"].deeplink').historyTabs();
317
- init_bs5_dropdowns();
318
-
319
- // Initialize Sliders - https://stackoverflow.com/a/31083391
320
- var sliderSections = document.getElementsByClassName("range-slider");
321
- for (var x = 0; x < sliderSections.length; x++) {
322
- var sliders = sliderSections[x].getElementsByTagName("input");
323
- for (var y = 0; y < sliders.length; y++) {
324
- if (sliders[y].type === "range") {
325
- sliders[y].oninput = function () {
326
- // Get slider values
327
- var parent = this.parentNode;
328
- var slides = parent.getElementsByTagName("input");
329
- var slide1 = parseFloat(slides[0].value);
330
- var slide2 = parseFloat(slides[1].value);
331
- // Neither slider will clip the other, so make sure we determine which is larger
332
- if (slide1 > slide2) {
333
- var tmp = slide2;
334
- slide2 = slide1;
335
- slide1 = tmp;
336
- }
337
-
338
- var displayElement = parent.getElementsByClassName("rangeValues")[0];
339
- displayElement.innerHTML = slide1 + " - " + slide2;
340
- };
341
- // Manually trigger event first time to display values
342
- sliders[y].oninput();
343
- }
344
- }
345
- }
346
- }
347
-
348
- $(initialize_page);
349
-
350
- function enable_codemirror(f) {
351
- $("<link/>", {
352
- rel: "stylesheet",
353
- type: "text/css",
354
- href: `/static_assets/${_sc_version_tag}/codemirror.css`,
355
- }).appendTo("head");
356
- $.ajax({
357
- url: `/static_assets/${_sc_version_tag}/codemirror.min.js`,
358
- dataType: "script",
359
- cache: true,
360
- success: f,
361
- });
362
- }
363
12
 
364
13
  //https://stackoverflow.com/a/6021027
365
14
  function updateQueryStringParameter(uri1, key, value) {
@@ -474,23 +123,6 @@ function href_to(href) {
474
123
  function clear_state() {
475
124
  pjax_to(window.location.href.split("?")[0]);
476
125
  }
477
- function tristateClick(nm) {
478
- var current = $(`button#trib${nm}`).html();
479
- switch (current) {
480
- case "?":
481
- $(`button#trib${nm}`).html("T");
482
- $(`input#input${nm}`).val("on");
483
- break;
484
- case "T":
485
- $(`button#trib${nm}`).html("F");
486
- $(`input#input${nm}`).val("off");
487
- break;
488
- default:
489
- $(`button#trib${nm}`).html("?");
490
- $(`input#input${nm}`).val("?");
491
- break;
492
- }
493
- }
494
126
 
495
127
  function ajax_done(res) {
496
128
  common_done(res);
@@ -619,43 +251,17 @@ function applyViewConfig(e, url) {
619
251
  return false;
620
252
  }
621
253
 
622
- const repeaterCopyValuesToForm = (form, editor) => {
623
- const vs = JSON.parse(editor.getString());
624
- const allNames = new Set([]);
625
- const setVal = (k, ix, v) => {
626
- const $e = form.find(`input[name="${k}_${ix}"]`);
627
- if ($e.length) $e.val(v);
628
- else
629
- form.append(
630
- `<input type="hidden" name="${k}_${ix}" value="${v}"></input>`
631
- );
632
- };
633
- vs.forEach((v, ix) => {
634
- Object.entries(v).forEach(([k, v]) => {
635
- //console.log(ix, k, typeof v, v)
636
- allNames.add(k);
637
- if (typeof v === "boolean") setVal(k, ix, v ? "on" : "");
638
- else setVal(k, ix, v);
639
- });
640
- });
641
- //delete
642
- [...allNames].forEach((k) => {
643
- for (let ix = vs.length; ix < vs.length + 20; ix++) {
644
- $(`input[name=${k}_${ix}]`).remove();
645
- }
646
- });
647
- };
648
-
649
254
  function ajaxSubmitForm(e) {
650
255
  var form = $(e).closest("form");
651
256
  var url = form.attr("action");
652
- var form_data = form.serialize();
653
257
  $.ajax(url, {
654
258
  type: "POST",
655
259
  headers: {
656
260
  "CSRF-Token": _sc_globalCsrf,
657
261
  },
658
- data: form_data,
262
+ data: new FormData(form[0]),
263
+ processData: false,
264
+ contentType: false,
659
265
  success: function () {
660
266
  var no_reload = $("#scmodal").hasClass("no-submit-reload");
661
267
  $("#scmodal").modal("hide");
@@ -754,26 +360,6 @@ function test_formula(tablename, stored) {
754
360
  },
755
361
  });
756
362
  }
757
- function align_dropdown(id) {
758
- setTimeout(() => {
759
- if ($("#dm" + id).hasClass("show")) {
760
- var inputWidth = $("#search-input-group-" + id).outerWidth();
761
- $("#dm" + id).css("width", inputWidth);
762
- var d0pos = $("#search-input-group-" + id).offset();
763
- $("#dm" + id).offset({ left: d0pos.left });
764
- $(document).on("click", "#dm" + id, function (e) {
765
- e.stopPropagation();
766
- });
767
- }
768
- }, 0);
769
- }
770
-
771
- function remove_outline(form) {
772
- $(form)
773
- .find("button[type=submit]")
774
- .removeClass("btn-outline-primary")
775
- .addClass("btn-primary");
776
- }
777
363
 
778
364
  function init_room(viewname, room_id) {
779
365
  const socket = io({ transports: ["websocket"] });
@@ -843,25 +429,6 @@ async function fill_formula_btn_click(btn, k) {
843
429
  if (k) k();
844
430
  }
845
431
 
846
- const columnSummary = (col) => {
847
- if (!col) return "Unknown";
848
- switch (col.type) {
849
- case "Field":
850
- return `Field ${col.field_name} ${col.fieldview || ""}`;
851
- case "Link":
852
- return `Link ${col.link_text}`;
853
- case "JoinField":
854
- return `Join ${col.join_field}`;
855
- case "ViewLink":
856
- return `View link ${col.view_label || col.view.split(":")[1] || ""}`;
857
- case "Action":
858
- return `Action ${col.action_label || col.action_name}`;
859
- case "Aggregation":
860
- return `${col.stat} ${col.agg_field} ${col.agg_relation}`;
861
- default:
862
- return "Unknown";
863
- }
864
- };
865
432
 
866
433
  /*
867
434
  https://github.com/jeffdavidgreen/bootstrap-html5-history-tabs/blob/master/bootstrap-history-tabs.js
package/routes/admin.js CHANGED
@@ -23,9 +23,6 @@ const {
23
23
  div,
24
24
  a,
25
25
  hr,
26
- form,
27
- input,
28
- label,
29
26
  i,
30
27
  h4,
31
28
  table,
@@ -33,7 +30,6 @@ const {
33
30
  td,
34
31
  th,
35
32
  tr,
36
- button,
37
33
  span,
38
34
  p,
39
35
  code,
@@ -45,7 +41,7 @@ const {
45
41
  getState,
46
42
  restart_tenant,
47
43
  getTenant,
48
- get_other_domain_tenant,
44
+ //get_other_domain_tenant,
49
45
  get_process_init_time,
50
46
  } = require("@saltcorn/data/db/state");
51
47
  const { loadAllPlugins } = require("../load_plugins");
@@ -61,7 +57,7 @@ const load_plugins = require("../load_plugins");
61
57
  const {
62
58
  restore_backup,
63
59
  send_admin_page,
64
- send_files_page,
60
+ //send_files_page,
65
61
  config_fields_form,
66
62
  save_config_from_form,
67
63
  flash_restart_if_required,
@@ -90,8 +86,9 @@ const router = new Router();
90
86
  module.exports = router;
91
87
 
92
88
  /**
93
- * @param {object} req
94
- * @returns {Promise<Form>}
89
+ * Site identity form
90
+ * @param {object} req -http request
91
+ * @returns {Promise<Form>} form
95
92
  */
96
93
  const site_id_form = (req) =>
97
94
  config_fields_form({
@@ -106,13 +103,15 @@ const site_id_form = (req) =>
106
103
  "page_custom_html",
107
104
  "development_mode",
108
105
  "log_sql",
106
+ "plugins_store_endpoint",
107
+ "packs_store_endpoint",
109
108
  ...(getConfigFile() ? ["multitenancy_enabled"] : []),
110
109
  ],
111
110
  action: "/admin",
112
111
  submitLabel: req.__("Save"),
113
112
  });
114
113
  /**
115
- * Email settings form definition
114
+ * Email settings form
116
115
  * @param {object} req request
117
116
  * @returns {Promise<Form>} form
118
117
  */
@@ -137,6 +136,7 @@ const email_form = async (req) => {
137
136
  };
138
137
 
139
138
  /**
139
+ * Router get /
140
140
  * @name get
141
141
  * @function
142
142
  * @memberof module:routes/admin~routes/adminRouter
@@ -145,7 +145,6 @@ router.get(
145
145
  "/",
146
146
  isAdmin,
147
147
  error_catcher(async (req, res) => {
148
- const isRoot = db.getTenantSchema() === db.connectObj.default_schema;
149
148
  const form = await site_id_form(req);
150
149
  send_admin_page({
151
150
  res,
@@ -527,6 +526,9 @@ router.post(
527
526
  }
528
527
  })
529
528
  );
529
+ /**
530
+ * /check-for-updates
531
+ */
530
532
  router.post(
531
533
  "/check-for-upgrade",
532
534
  isAdmin,
@@ -548,8 +550,8 @@ router.post(
548
550
  const fileName = await create_backup();
549
551
  res.type("application/zip");
550
552
  res.attachment(fileName);
551
- var file = fs.createReadStream(fileName);
552
- file.on("end", function () {
553
+ const file = fs.createReadStream(fileName);
554
+ file.on("end", function () {
553
555
  fs.unlink(fileName, function () {});
554
556
  });
555
557
  file.pipe(res);
@@ -579,8 +581,9 @@ router.post(
579
581
  );
580
582
 
581
583
  /**
584
+ * Clear All Form
582
585
  * @param {object} req
583
- * @returns {Form}
586
+ * @returns {Form} form
584
587
  */
585
588
  const clearAllForm = (req) =>
586
589
  new Form({
@@ -694,6 +697,7 @@ router.post(
694
697
  try {
695
698
  const file_store = db.connectObj.file_store;
696
699
  const admin_users = await User.find({ role_id: 1 }, { orderBy: "id" });
700
+ // greenlock logic
697
701
  const Greenlock = require("greenlock");
698
702
  const greenlock = Greenlock.create({
699
703
  packageRoot: path.resolve(__dirname, ".."),
@@ -709,6 +713,7 @@ router.post(
709
713
  subject: domain,
710
714
  altnames,
711
715
  });
716
+ // letsencrypt
712
717
  await getState().setConfig("letsencrypt", true);
713
718
  req.flash(
714
719
  "success",
@@ -758,7 +763,9 @@ router.get(
758
763
  });
759
764
  })
760
765
  );
761
-
766
+ /**
767
+ * /confiuration-check
768
+ */
762
769
  router.get(
763
770
  "/configuration-check",
764
771
  isAdmin,
@@ -863,6 +870,7 @@ router.post(
863
870
  if (form.values.plugins) {
864
871
  const ps = await Plugin.find();
865
872
  for (const p of ps) {
873
+ // todo configurable list of mandatory plugins
866
874
  if (!["base", "sbadmin2"].includes(p.name)) await p.delete();
867
875
  }
868
876
  await getState().refresh_plugins();
@@ -902,6 +910,8 @@ router.post(
902
910
  req.logout();
903
911
  req.session = null;
904
912
  }
913
+ // todo make configurable - redirect to create first user
914
+ // redirect to create first user
905
915
  res.redirect(`/auth/create_first_user`);
906
916
  } else {
907
917
  req.flash(