@saltcorn/server 0.8.0-beta.0 → 0.8.0-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/routes/list.js CHANGED
@@ -11,9 +11,8 @@
11
11
  const Router = require("express-promise-router");
12
12
 
13
13
  const db = require("@saltcorn/data/db");
14
- const { mkTable, h, link, post_btn } = require("@saltcorn/markup");
14
+ const { mkTable, link, post_btn } = require("@saltcorn/markup");
15
15
  const {
16
- a,
17
16
  script,
18
17
  domReady,
19
18
  div,
@@ -27,7 +26,6 @@ const {
27
26
  const Table = require("@saltcorn/data/models/table");
28
27
  const { isAdmin, error_catcher } = require("./utils");
29
28
  const moment = require("moment");
30
- const { readState } = require("@saltcorn/data/plugin-helper");
31
29
 
32
30
  /**
33
31
  * @type {object}
@@ -49,11 +47,11 @@ module.exports = router;
49
47
  * @function
50
48
  */
51
49
  router.get(
52
- "/_versions/:name/:id",
50
+ "/_versions/:tableName/:id",
53
51
  isAdmin,
54
52
  error_catcher(async (req, res) => {
55
- const { name, id } = req.params;
56
- const table = await Table.findOne({ name });
53
+ const { tableName, id } = req.params;
54
+ const table = await Table.findOne({ name : tableName });
57
55
 
58
56
  const fields = await table.getFields();
59
57
  var tfields = fields.map((f) => ({ label: f.label, key: f.listKey }));
@@ -97,11 +95,11 @@ router.get(
97
95
  * @function
98
96
  */
99
97
  router.post(
100
- "/_restore/:name/:id/:_version",
98
+ "/_restore/:tableName/:id/:_version",
101
99
  isAdmin,
102
100
  error_catcher(async (req, res) => {
103
- const { name, id, _version } = req.params;
104
- const table = await Table.findOne({ name });
101
+ const { tableName, id, _version } = req.params;
102
+ const table = await Table.findOne({ name : tableName });
105
103
 
106
104
  const fields = await table.getFields();
107
105
  const row = await db.selectOne(`${db.sqlsanitize(table.name)}__history`, {
@@ -246,6 +244,7 @@ router.get(
246
244
  }
247
245
 
248
246
  //console.log(fields);
247
+ // todo remove keyfields - unused
249
248
  const keyfields = fields
250
249
  .filter((f) => f.type === "Key" || f.type === "File")
251
250
  .map((f) => ({ name: f.name, type: f.reftype }));
package/routes/tables.js CHANGED
@@ -8,7 +8,6 @@ const Router = require("express-promise-router");
8
8
 
9
9
  const db = require("@saltcorn/data/db");
10
10
  const Table = require("@saltcorn/data/models/table");
11
- const Field = require("@saltcorn/data/models/field");
12
11
  const File = require("@saltcorn/data/models/file");
13
12
  const View = require("@saltcorn/data/models/view");
14
13
  const User = require("@saltcorn/data/models/user");
@@ -16,7 +15,6 @@ const {
16
15
  mkTable,
17
16
  renderForm,
18
17
  link,
19
- post_btn,
20
18
  settingsDropdown,
21
19
  post_delete_btn,
22
20
  post_dropdown_item,
@@ -29,10 +27,7 @@ const { isAdmin, error_catcher, setTenant } = require("./utils.js");
29
27
  const Form = require("@saltcorn/data/models/form");
30
28
  const {
31
29
  span,
32
- h5,
33
30
  h4,
34
- h3,
35
- nbsp,
36
31
  p,
37
32
  a,
38
33
  div,
@@ -41,7 +36,6 @@ const {
41
36
  label,
42
37
  input,
43
38
  text,
44
- tr,
45
39
  script,
46
40
  domReady,
47
41
  code,
@@ -552,14 +546,13 @@ router.get(
552
546
  res.redirect(`/table`);
553
547
  return;
554
548
  }
555
- id = table.id;
556
549
  const nrows = await table.countRows();
557
550
  const fields = await table.getFields();
558
551
  const { child_relations } = await table.get_child_relations();
559
552
  const inbound_refs = [
560
553
  ...new Set(child_relations.map(({ table }) => table.name)),
561
554
  ];
562
- var fieldCard;
555
+ let fieldCard;
563
556
  if (fields.length === 0) {
564
557
  fieldCard = [
565
558
  h4(req.__(`No fields defined in %s table`, table.name)),
@@ -866,8 +859,10 @@ router.post(
866
859
  res.redirect(`/table/${table.id}`);
867
860
  }
868
861
  } else if (v.external) {
862
+ // todo check that works after where change
863
+ // todo findOne can be have parameter for external table here
869
864
  //we can only save min role
870
- const table = await Table.findOne(v.name);
865
+ const table = await Table.findOne( { name : v.name });
871
866
  if (table) {
872
867
  const exttables_min_role_read = getState().getConfigCopy(
873
868
  "exttables_min_role_read",
@@ -1148,6 +1143,7 @@ router.get(
1148
1143
  /**
1149
1144
  * Constraint Fields Edition Form
1150
1145
  * Choosing fields for adding to contrain
1146
+ * @param req
1151
1147
  * @param {string} table_id
1152
1148
  * @param {object[]} fields
1153
1149
  * @returns {Form}
package/routes/tenant.js CHANGED
@@ -44,7 +44,6 @@ const User = require("@saltcorn/data/models/user");
44
44
  const File = require("@saltcorn/data/models/file");
45
45
  const {
46
46
  send_infoarch_page,
47
- //send_admin_page,
48
47
  config_fields_form,
49
48
  save_config_from_form,
50
49
  } = require("../markup/admin.js");
@@ -87,11 +86,6 @@ const tenant_form = (req) =>
87
86
  input_type: "text",
88
87
  postText: text(req.hostname),
89
88
  },
90
- {
91
- name: "description",
92
- label: req.__("Description"),
93
- input_type: "text",
94
- },
95
89
  ],
96
90
  });
97
91
 
@@ -155,55 +149,56 @@ router.get(
155
149
  );
156
150
  let create_tenant_warning_text = "";
157
151
  if (getState().getConfig("create_tenant_warning")) {
158
- create_tenant_warning_text = getState().getConfig("create_tenant_warning_text");
159
- if (create_tenant_warning_text && create_tenant_warning_text.length > 0)
160
- create_tenant_warning_text = div(
161
- {
162
- class: "alert alert-warning alert-dismissible fade show mt-5",
163
- role: "alert",
164
- },
165
- h4(req.__("Warning")),
166
- p( create_tenant_warning_text
167
- )
168
- );
169
- else
170
- create_tenant_warning_text = div(
171
- {
172
- class: "alert alert-warning alert-dismissible fade show mt-5",
173
- role: "alert",
174
- },
175
- h4(req.__("Warning")),
176
- p(
177
- req.__(
178
- "Hosting on this site is provided for free and with no guarantee of availability or security of your application. "
179
- ) +
180
- " " +
181
- req.__(
182
- "This facility is intended solely for you to evaluate the suitability of Saltcorn. "
183
- ) +
184
- " " +
185
- req.__(
186
- "If you would like to store private information that needs to be secure, please use self-hosted Saltcorn. "
187
- ) +
188
- " " +
189
- req.__(
190
- 'See <a href="https://github.com/saltcorn/saltcorn">GitHub repository</a> for instructions<p>'
191
- )
192
- )
193
- );
152
+ create_tenant_warning_text = getState().getConfig(
153
+ "create_tenant_warning_text"
154
+ );
155
+ if (create_tenant_warning_text && create_tenant_warning_text.length > 0)
156
+ create_tenant_warning_text = div(
157
+ {
158
+ class: "alert alert-warning alert-dismissible fade show mt-5",
159
+ role: "alert",
160
+ },
161
+ h4(req.__("Warning")),
162
+ p(create_tenant_warning_text)
163
+ );
164
+ else
165
+ create_tenant_warning_text = div(
166
+ {
167
+ class: "alert alert-warning alert-dismissible fade show mt-5",
168
+ role: "alert",
169
+ },
170
+ h4(req.__("Warning")),
171
+ p(
172
+ req.__(
173
+ "Hosting on this site is provided for free and with no guarantee of availability or security of your application. "
174
+ ) +
175
+ " " +
176
+ req.__(
177
+ "This facility is intended solely for you to evaluate the suitability of Saltcorn. "
178
+ ) +
179
+ " " +
180
+ req.__(
181
+ "If you would like to store private information that needs to be secure, please use self-hosted Saltcorn. "
182
+ ) +
183
+ " " +
184
+ req.__(
185
+ 'See <a href="https://github.com/saltcorn/saltcorn">GitHub repository</a> for instructions<p>'
186
+ )
187
+ )
188
+ );
194
189
  }
195
190
 
196
191
  res.sendWrap(
197
192
  req.__("Create application"),
198
193
  create_tenant_warning_text +
199
- renderForm(tenant_form(req), req.csrfToken()) +
200
- p(
201
- { class: "mt-2" },
202
- req.__("To login to a previously created application, go to: "),
203
- code(`${req.protocol}://`) +
204
- i(req.__("Application name")) +
205
- code("." + req.hostname)
206
- )
194
+ renderForm(tenant_form(req), req.csrfToken()) +
195
+ p(
196
+ { class: "mt-2" },
197
+ req.__("To login to a previously created application, go to: "),
198
+ code(`${req.protocol}://`) +
199
+ i(req.__("Application name")) +
200
+ code("." + req.hostname)
201
+ )
207
202
  );
208
203
  })
209
204
  );
@@ -284,7 +279,15 @@ router.post(
284
279
  // tenant creator
285
280
  const user_email = req.user && req.user.email;
286
281
  // switch to tenant
287
- await switchToTenant(await insertTenant(subdomain, user_email, description, tenant_template), newurl);
282
+ await switchToTenant(
283
+ await insertTenant(
284
+ subdomain,
285
+ user_email,
286
+ description,
287
+ tenant_template
288
+ ),
289
+ newurl
290
+ );
288
291
  // add tenant to global state
289
292
  add_tenant(subdomain);
290
293
  await create_tenant({
@@ -319,13 +322,13 @@ router.post(
319
322
  " " +
320
323
  hasTemplate
321
324
  ? req.__(
322
- 'Use this link: <a href="%s">%s</a> to revisit your application at any time.',
323
- newurl,
324
- newurl
325
- )
325
+ 'Use this link: <a href="%s">%s</a> to revisit your application at any time.',
326
+ newurl,
327
+ newurl
328
+ )
326
329
  : req.__(
327
- "Use this link to revisit your application at any time."
328
- )
330
+ "Use this link to revisit your application at any time."
331
+ )
329
332
  )
330
333
  )
331
334
  );
@@ -508,14 +511,12 @@ const get_tenant_info = async (subdomain) => {
508
511
  // get tenant row
509
512
  const ten = await Tenant.findOne({ subdomain: saneDomain });
510
513
  if (ten) {
511
- info.description = ten.description;
512
- info.created = ten.created;
514
+ info.description = ten.description;
515
+ info.created = ten.created;
513
516
  }
514
517
 
515
-
516
518
  // get data from tenant schema
517
519
  return await db.runWithTenant(saneDomain, async () => {
518
-
519
520
  // TBD fix the first user issue because not always firt user by id is creator of tenant
520
521
  const firstUser = await User.find({}, { orderBy: "id", limit: 1 });
521
522
  if (firstUser && firstUser.length > 0) {
@@ -673,7 +674,10 @@ router.get(
673
674
  type: "String",
674
675
  },
675
676
  ],
676
- values: { base_url: info.base_url, description: info.description },
677
+ values: {
678
+ base_url: info.base_url,
679
+ description: info.description,
680
+ },
677
681
  }),
678
682
  req.csrfToken()
679
683
  ),
@@ -731,9 +735,7 @@ router.post(
731
735
 
732
736
  // save description
733
737
  const { description } = req.body;
734
- await Tenant.update( saneDomain, {description: description});
735
-
736
-
738
+ await Tenant.update(saneDomain, { description: description });
737
739
 
738
740
  await db.runWithTenant(saneDomain, async () => {
739
741
  await getState().setConfig("base_url", base_url);
package/routes/view.js CHANGED
@@ -9,8 +9,7 @@ const Router = require("express-promise-router");
9
9
  const View = require("@saltcorn/data/models/view");
10
10
  const Table = require("@saltcorn/data/models/table");
11
11
 
12
- const { div, text, i, a } = require("@saltcorn/markup/tags");
13
- const { renderForm, link } = require("@saltcorn/markup");
12
+ const { text } = require("@saltcorn/markup/tags");
14
13
  const {
15
14
  isAdmin,
16
15
  error_catcher,
@@ -104,7 +103,8 @@ router.post(
104
103
  if (sf.required && !query[sf.name]) {
105
104
  if (!row) {
106
105
  if (!table)
107
- table = await Table.findOne(view.table_id || view.exttable_name);
106
+ // todo check after where change
107
+ table = await Table.findOne(view.table_id ? { id : view.table_id } : {name: view.exttable_name});
108
108
  row = await table.getRow({});
109
109
  }
110
110
  if (row) query[sf.name] = row[sf.name];
@@ -7,30 +7,8 @@
7
7
 
8
8
  const Router = require("express-promise-router");
9
9
 
10
- const {
11
- renderForm,
12
- mkTable,
13
- link,
14
- //post_btn,
15
- //post_delete_btn,
16
- post_dropdown_item,
17
- renderBuilder,
18
- settingsDropdown,
19
- alert,
20
- } = require("@saltcorn/markup");
21
- const {
22
- //span,
23
- //h5,
24
- h4,
25
- //nbsp,
26
- p,
27
- a,
28
- div,
29
- //button,
30
- script,
31
- text,
32
- domReady,
33
- } = require("@saltcorn/markup/tags");
10
+ const { renderForm, renderBuilder, alert } = require("@saltcorn/markup");
11
+ const { p, a, div, script, text, domReady } = require("@saltcorn/markup/tags");
34
12
 
35
13
  const { getState } = require("@saltcorn/data/db/state");
36
14
  const { isAdmin, error_catcher, addOnDoneRedirect } = require("./utils.js");
@@ -89,14 +67,15 @@ router.get(
89
67
  const accessWarning =
90
68
  hasAccessWarning.length > 0
91
69
  ? alert(
92
- "danger",
93
- `<p>You have views with a role to access lower than the table role to read,
70
+ "danger",
71
+ req.__(
72
+ `<p>You have views with a role to access lower than the table role to read,
94
73
  with no table ownership. In the next version of Saltcorn, this may cause a
95
74
  denial of access. Users will need to have table read access to any data displayed.</p>
96
- Views potentially affected: ${hasAccessWarning
97
- .map((v) => v.name)
98
- .join(", ")}`
99
- )
75
+ Views potentially affected: %s`,
76
+ hasAccessWarning.map((v) => v.name).join(", ")
77
+ )
78
+ )
100
79
  : "";
101
80
  res.sendWrap(req.__(`Views`), {
102
81
  above: [
@@ -113,14 +92,14 @@ router.get(
113
92
  viewMarkup,
114
93
  tables.length > 0
115
94
  ? a(
116
- { href: `/viewedit/new`, class: "btn btn-primary" },
117
- req.__("Create view")
118
- )
119
- : p(
120
- req.__(
121
- "You must create at least one table before you can create views."
95
+ { href: `/viewedit/new`, class: "btn btn-primary" },
96
+ req.__("Create view")
122
97
  )
123
- ),
98
+ : p(
99
+ req.__(
100
+ "You must create at least one table before you can create views."
101
+ )
102
+ ),
124
103
  ],
125
104
  },
126
105
  ],
@@ -232,15 +211,15 @@ const viewForm = async (req, tableOptions, roles, pages, values) => {
232
211
  }),
233
212
  ...(isEdit
234
213
  ? [
235
- new Field({
236
- name: "viewtemplate",
237
- input_type: "hidden",
238
- }),
239
- new Field({
240
- name: "table_name",
241
- input_type: "hidden",
242
- }),
243
- ]
214
+ new Field({
215
+ name: "viewtemplate",
216
+ input_type: "hidden",
217
+ }),
218
+ new Field({
219
+ name: "table_name",
220
+ input_type: "hidden",
221
+ }),
222
+ ]
244
223
  : []),
245
224
  ],
246
225
  values,
@@ -259,7 +238,7 @@ router.get(
259
238
  error_catcher(async (req, res) => {
260
239
  const { viewname } = req.params;
261
240
 
262
- var viewrow = await View.findOne({ name: viewname });
241
+ const viewrow = await View.findOne({ name: viewname });
263
242
  if (!viewrow) {
264
243
  req.flash("error", `View not found: ${text(viewname)}`);
265
244
  res.redirect("/viewedit");
@@ -387,8 +366,8 @@ router.post(
387
366
  sendForm(form);
388
367
  } else {
389
368
  const existing_view = await View.findOne({ name: result.success.name });
390
- if (typeof existing_view !== "undefined")
391
- if (req.body.id != existing_view.id) {
369
+ if (existing_view)
370
+ if (+req.body.id !== existing_view.id) {
392
371
  // may be need !== but doesnt work
393
372
  form.errors.name = req.__("A view with this name already exists");
394
373
  form.hasErrors = true;
@@ -409,7 +388,7 @@ router.post(
409
388
  const slug = slugOptions.find((so) => so.label === v.slug);
410
389
  v.slug = slug || null;
411
390
  }
412
- const table = await Table.findOne({ name: v.table_name });
391
+ //const table = await Table.findOne({ name: v.table_name });
413
392
  delete v.table_name;
414
393
  if (req.body.id) {
415
394
  await View.update(v, +req.body.id);
@@ -457,12 +436,18 @@ const respondWorkflow = (view, wf, wfres, req, res) => {
457
436
  title: wfres.title,
458
437
  contents,
459
438
  },
460
- ...previewURL ? [{
461
- type: "card",
462
- title: req.__("Preview"),
463
- contents: div({ id: "viewcfg-preview", "data-preview-url": previewURL },
464
- script(domReady(`updateViewPreview()`))),
465
- }] : []
439
+ ...(previewURL
440
+ ? [
441
+ {
442
+ type: "card",
443
+ title: req.__("Preview"),
444
+ contents: div(
445
+ { id: "viewcfg-preview", "data-preview-url": previewURL },
446
+ script(domReady(`updateViewPreview()`))
447
+ ),
448
+ },
449
+ ]
450
+ : []),
466
451
  ],
467
452
  });
468
453
  if (wfres.flash) req.flash(wfres.flash[0], wfres.flash[1]);
@@ -485,7 +470,11 @@ const respondWorkflow = (view, wf, wfres, req, res) => {
485
470
  },
486
471
  ],
487
472
  },
488
- wrap(renderForm(wfres.renderForm, req.csrfToken()), false, wfres.previewURL)
473
+ wrap(
474
+ renderForm(wfres.renderForm, req.csrfToken()),
475
+ false,
476
+ wfres.previewURL
477
+ )
489
478
  );
490
479
  else if (wfres.renderBuilder) {
491
480
  wfres.renderBuilder.options.view_id = view.id;
@@ -1,13 +1,13 @@
1
1
  const request = require("supertest");
2
2
  const getApp = require("../app");
3
3
  const {
4
- getStaffLoginCookie,
4
+ //getStaffLoginCookie,
5
5
  getAdminLoginCookie,
6
6
  toRedirect,
7
7
  itShouldRedirectUnauthToLogin,
8
8
  toInclude,
9
9
  toSucceed,
10
- toNotInclude,
10
+ //toNotInclude,
11
11
  resetToFixtures,
12
12
  respondJsonWith,
13
13
  } = require("../auth/testhelp");
@@ -79,6 +79,8 @@ describe("admin page", () => {
79
79
  ["/roleadmin", "Theme"],
80
80
  ["/useradmin/settings", "Authentication settings"],
81
81
  ["/useradmin/ssl", "HTTPS encryption"],
82
+ ["/useradmin/http", "HTTP settings"],
83
+ ["/useradmin/permissions", "Permissions settings"],
82
84
  ]);
83
85
  adminPageContains([
84
86
  ["/menu", "jquery-menu-editor"],
@@ -141,6 +141,7 @@ describe("Field Endpoints", () => {
141
141
  .send("stepName=Summary")
142
142
  .send("contextEnc=" + ctx)
143
143
  .send("summary_field=pages")
144
+ .send("on_delete=Fail")
144
145
  .set("Cookie", loginCookie)
145
146
  .expect(toRedirect("/table/2"));
146
147
  });
@@ -1,3 +1,4 @@
1
+ // File: tenant.test.js
1
2
  const db = require("@saltcorn/data/db");
2
3
  const request = require("supertest");
3
4
 
@@ -40,6 +41,7 @@ describe("tenant routes", () => {
40
41
  .send("subdomain=test2")
41
42
  .expect(toInclude("Success"));
42
43
  });
44
+
43
45
  it("creates tenant with capital letter", async () => {
44
46
  db.enable_multi_tenant();
45
47
  await getState().setConfig("role_to_create_tenant", "10");
@@ -51,6 +53,7 @@ describe("tenant routes", () => {
51
53
  .expect(toInclude("Success"));
52
54
  db.set_sql_logging(false);
53
55
  });
56
+
54
57
  it("rejects existing tenant", async () => {
55
58
  db.enable_multi_tenant();
56
59
  await getState().setConfig("role_to_create_tenant", "10");
@@ -71,6 +74,7 @@ describe("tenant routes", () => {
71
74
  .set("Cookie", loginCookie)
72
75
  .expect(toInclude("peashoot"));
73
76
  });
77
+
74
78
  it("show tenant info", async () => {
75
79
  const loginCookie = await getAdminLoginCookie();
76
80
 
@@ -80,6 +84,7 @@ describe("tenant routes", () => {
80
84
  .set("Cookie", loginCookie)
81
85
  .expect(toInclude("E-mail"));
82
86
  });
87
+
83
88
  it("delete tenant", async () => {
84
89
  const loginCookie = await getAdminLoginCookie();
85
90
 
@@ -89,9 +94,12 @@ describe("tenant routes", () => {
89
94
  .set("Cookie", loginCookie)
90
95
  .expect(toRedirect("/tenant/list"));
91
96
  });
97
+
92
98
  } else {
99
+
93
100
  it("does not support tenants on SQLite", async () => {
94
101
  expect(db.isSQLite).toBe(true);
95
102
  });
103
+
96
104
  }
97
105
  });
@@ -43,6 +43,20 @@ describe("viewedit edit endpoint", () => {
43
43
  .set("Cookie", loginCookie)
44
44
  .expect(toInclude("author"));
45
45
  });
46
+ it("direct edit to config", async () => {
47
+ const loginCookie = await getAdminLoginCookie();
48
+ const app = await getApp({ disableCsrf: true });
49
+ const v = await View.findOne({ name: "authorlist" });
50
+ await request(app)
51
+ .post("/viewedit/save")
52
+ .send("viewtemplate=List")
53
+ .send("table_name=books")
54
+ .send("id=" + v.id)
55
+ .send("name=authorlist")
56
+ .send("min_role=10")
57
+ .set("Cookie", loginCookie)
58
+ .expect(toRedirect("/viewedit/config/authorlist"));
59
+ });
46
60
  it("show list editor", async () => {
47
61
  const loginCookie = await getAdminLoginCookie();
48
62
  const app = await getApp({ disableCsrf: true });
@@ -478,6 +492,6 @@ describe("Library", () => {
478
492
  .get("/library/list")
479
493
  .set("Cookie", loginCookie)
480
494
  .expect(toInclude("Library"))
481
- .expect(toNotInclude("ShinyCard"))
495
+ .expect(toNotInclude("ShinyCard"));
482
496
  });
483
497
  });