@saltcorn/server 0.8.5-beta.2 → 0.8.5-beta.4

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/tables.js CHANGED
@@ -439,8 +439,7 @@ router.get(
439
439
  title: req.__("Tables"),
440
440
  headers: [
441
441
  {
442
- script:
443
- "https://unpkg.com/vis-network@9.1.2/standalone/umd/vis-network.min.js",
442
+ script: `/static_assets/${db.connectObj.version_tag}/vis-network.min.js`,
444
443
  },
445
444
  ],
446
445
  },
@@ -762,18 +761,22 @@ router.get(
762
761
  })
763
762
  )
764
763
  ),
764
+ !table.external &&
765
+ div(
766
+ { class: "mx-auto" },
767
+ a(
768
+ { href: `/table/constraints/${table.id}` },
769
+ i({ class: "fas fa-2x fa-tasks" }),
770
+ "<br/>",
771
+ req.__("Constraints")
772
+ )
773
+ ),
774
+
765
775
  // only if table is not external
766
776
  !table.external &&
767
777
  div(
768
778
  { class: "mx-auto" },
769
779
  settingsDropdown(`dataMenuButton`, [
770
- a(
771
- {
772
- class: "dropdown-item",
773
- href: `/table/constraints/${table.id}`,
774
- },
775
- '<i class="fas fa-ban"></i>&nbsp;' + req.__("Constraints")
776
- ),
777
780
  // rename table doesnt supported for sqlite
778
781
  !db.isSQLite &&
779
782
  table.name !== "users" &&
@@ -1154,8 +1157,15 @@ router.get(
1154
1157
  [
1155
1158
  { label: req.__("Type"), key: "type" },
1156
1159
  {
1157
- label: req.__("Fields"),
1158
- key: (r) => r.configuration.fields.join(", "),
1160
+ label: req.__("What"),
1161
+ key: (r) =>
1162
+ r.type === "Unique"
1163
+ ? r.configuration.fields.join(", ")
1164
+ : r.type === "Index"
1165
+ ? r.configuration.field
1166
+ : r.type === "Formula"
1167
+ ? r.configuration.formula
1168
+ : "",
1159
1169
  },
1160
1170
  {
1161
1171
  label: req.__("Delete"),
@@ -1166,7 +1176,12 @@ router.get(
1166
1176
  cons,
1167
1177
  { hover: true }
1168
1178
  ),
1169
- link(`/table/add-constraint/${id}`, req.__("Add constraint")),
1179
+ req.__("Add constraint: "),
1180
+ link(`/table/add-constraint/${id}/Unique`, req.__("Unique")),
1181
+ " | ",
1182
+ link(`/table/add-constraint/${id}/Formula`, req.__("Formula")),
1183
+ " | ",
1184
+ link(`/table/add-constraint/${id}/Index`, req.__("Index")),
1170
1185
  ],
1171
1186
  },
1172
1187
  ],
@@ -1181,18 +1196,68 @@ router.get(
1181
1196
  * @param {object[]} fields
1182
1197
  * @returns {Form}
1183
1198
  */
1184
- const constraintForm = (req, table_id, fields) =>
1185
- new Form({
1186
- action: `/table/add-constraint/${table_id}`,
1187
- blurb: req.__(
1188
- "Tick the boxes for the fields that should be jointly unique"
1189
- ),
1190
- fields: fields.map((f) => ({
1191
- name: f.name,
1192
- label: f.label,
1193
- type: "Bool",
1194
- })),
1195
- });
1199
+ const constraintForm = (req, table_id, fields, type) => {
1200
+ switch (type) {
1201
+ case "Formula":
1202
+ return new Form({
1203
+ action: `/table/add-constraint/${table_id}/${type}`,
1204
+
1205
+ fields: [
1206
+ {
1207
+ name: "formula",
1208
+ label: req.__("Constraint formula"),
1209
+ validator: expressionValidator,
1210
+ type: "String",
1211
+ class: "validate-expression",
1212
+ sublabel:
1213
+ req.__(
1214
+ "Formula must evaluate to true for valid rows. In scope: "
1215
+ ) +
1216
+ fields
1217
+ .map((f) => f.name)
1218
+ .map((fn) => code(fn))
1219
+ .join(", "),
1220
+ },
1221
+ {
1222
+ name: "errormsg",
1223
+ label: "Error message",
1224
+ sublabel: "Shown the user if formula is false",
1225
+ type: "String",
1226
+ },
1227
+ ],
1228
+ });
1229
+ case "Unique":
1230
+ return new Form({
1231
+ action: `/table/add-constraint/${table_id}/${type}`,
1232
+ blurb: req.__(
1233
+ "Tick the boxes for the fields that should be jointly unique"
1234
+ ),
1235
+ fields: fields.map((f) => ({
1236
+ name: f.name,
1237
+ label: f.label,
1238
+ type: "Bool",
1239
+ })),
1240
+ });
1241
+ case "Index":
1242
+ return new Form({
1243
+ action: `/table/add-constraint/${table_id}/${type}`,
1244
+ blurb: req.__(
1245
+ "Choose the field to be indexed. This make searching the table faster."
1246
+ ),
1247
+ fields: [
1248
+ {
1249
+ type: "String",
1250
+ name: "field",
1251
+ label: "Field",
1252
+ required: true,
1253
+ attributes: {
1254
+ options: fields.map((f) => ({ label: f.label, name: f.name })),
1255
+ },
1256
+ },
1257
+ ],
1258
+ });
1259
+ }
1260
+ };
1196
1261
 
1197
1262
  /**
1198
1263
  * Add constraint GET handler
@@ -1203,10 +1268,10 @@ const constraintForm = (req, table_id, fields) =>
1203
1268
  * @function
1204
1269
  */
1205
1270
  router.get(
1206
- "/add-constraint/:id",
1271
+ "/add-constraint/:id/:type",
1207
1272
  isAdmin,
1208
1273
  error_catcher(async (req, res) => {
1209
- const { id } = req.params;
1274
+ const { id, type } = req.params;
1210
1275
  const table = await Table.findOne({ id });
1211
1276
  if (!table) {
1212
1277
  req.flash("error", `Table not found`);
@@ -1214,7 +1279,7 @@ router.get(
1214
1279
  return;
1215
1280
  }
1216
1281
  const fields = await table.getFields();
1217
- const form = constraintForm(req, table.id, fields);
1282
+ const form = constraintForm(req, table.id, fields, type);
1218
1283
  res.sendWrap(req.__(`Add constraint to %s`, table.name), {
1219
1284
  above: [
1220
1285
  {
@@ -1231,7 +1296,7 @@ router.get(
1231
1296
  },
1232
1297
  {
1233
1298
  type: "card",
1234
- title: req.__(`Add constraint to %s`, table.name),
1299
+ title: req.__(`Add %s constraint to %s`, type, table.name),
1235
1300
  contents: renderForm(form, req.csrfToken()),
1236
1301
  },
1237
1302
  ],
@@ -1247,10 +1312,10 @@ router.get(
1247
1312
  * @function
1248
1313
  */
1249
1314
  router.post(
1250
- "/add-constraint/:id",
1315
+ "/add-constraint/:id/:type",
1251
1316
  isAdmin,
1252
1317
  error_catcher(async (req, res) => {
1253
- const { id } = req.params;
1318
+ const { id, type } = req.params;
1254
1319
  const table = await Table.findOne({ id });
1255
1320
  if (!table) {
1256
1321
  req.flash("error", `Table not found`);
@@ -1258,16 +1323,20 @@ router.post(
1258
1323
  return;
1259
1324
  }
1260
1325
  const fields = await table.getFields();
1261
- const form = constraintForm(req, table.id, fields);
1326
+ const form = constraintForm(req, table.id, fields, type);
1262
1327
  form.validate(req.body);
1263
1328
  if (form.hasErrors) req.flash("error", req.__("An error occurred"));
1264
1329
  else {
1330
+ let configuration = {};
1331
+ if (type === "Unique")
1332
+ configuration.fields = fields
1333
+ .map((f) => f.name)
1334
+ .filter((f) => form.values[f]);
1335
+ else configuration = form.values;
1265
1336
  await TableConstraint.create({
1266
1337
  table_id: table.id,
1267
- type: "Unique",
1268
- configuration: {
1269
- fields: fields.map((f) => f.name).filter((f) => form.values[f]),
1270
- },
1338
+ type,
1339
+ configuration,
1271
1340
  });
1272
1341
  }
1273
1342
  res.redirect(`/table/constraints/${table.id}`);
package/routes/tenant.js CHANGED
@@ -426,6 +426,10 @@ const tenant_settings_form = (req) =>
426
426
  "create_tenant_warning",
427
427
  "create_tenant_warning_text",
428
428
  "tenant_template",
429
+ { section_header: "Tenant application capabilities" },
430
+ "tenants_install_git",
431
+ "tenants_set_npm_modules",
432
+ "tenants_unsafe_plugins",
429
433
  ],
430
434
  action: "/tenant/settings",
431
435
  submitLabel: req.__("Save"),
package/routes/utils.js CHANGED
@@ -18,6 +18,24 @@ 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 si = require("systeminformation");
22
+
23
+ const get_sys_info = async () => {
24
+ const disks = await si.fsSize();
25
+ let size = 0;
26
+ let used = 0;
27
+ disks.forEach((d) => {
28
+ if (d && d.used && d.size) {
29
+ size += d.size;
30
+ used += d.used;
31
+ }
32
+ });
33
+ const diskUsage = Math.round(100 * (used / size));
34
+ const simem = await si.mem();
35
+ const memUsage = Math.round(100 - 100 * (simem.available / simem.total));
36
+ const cpuUsage = Math.round((await si.currentLoad()).currentLoad);
37
+ return { memUsage, diskUsage, cpuUsage };
38
+ };
21
39
 
22
40
  /**
23
41
  * Checks that user logged or not.
@@ -314,4 +332,5 @@ module.exports = {
314
332
  get_tenant_from_req,
315
333
  addOnDoneRedirect,
316
334
  is_relative_url,
335
+ get_sys_info,
317
336
  };
package/tests/api.test.js CHANGED
@@ -19,7 +19,7 @@ beforeAll(async () => {
19
19
  afterAll(db.close);
20
20
 
21
21
  describe("API read", () => {
22
- it("should get books for public", async () => {
22
+ it("should get books for public simple", async () => {
23
23
  const app = await getApp({ disableCsrf: true });
24
24
  await request(app)
25
25
  .get("/api/books/")
@@ -32,7 +32,7 @@ describe("API read", () => {
32
32
  )
33
33
  );
34
34
  });
35
- it("should get books for public", async () => {
35
+ it("should get books for public fts", async () => {
36
36
  const app = await getApp({ disableCsrf: true });
37
37
  await request(app)
38
38
  .get("/api/books/?_fts=Herman")
@@ -5,11 +5,13 @@ const Field = require("@saltcorn/data/models/field");
5
5
  const {
6
6
  getStaffLoginCookie,
7
7
  getAdminLoginCookie,
8
+ getUserLoginCookie,
8
9
  itShouldRedirectUnauthToLogin,
9
10
  toInclude,
10
11
  toNotInclude,
11
12
  toRedirect,
12
13
  resetToFixtures,
14
+ succeedJsonWith,
13
15
  } = require("../auth/testhelp");
14
16
  const db = require("@saltcorn/data/db");
15
17
  const User = require("@saltcorn/data/models/user");
@@ -198,11 +200,11 @@ Gordon Kane, 217`;
198
200
  .set("Cookie", loginCookie)
199
201
  .expect(toInclude("books constraints"));
200
202
  await request(app)
201
- .get("/table/add-constraint/" + id)
203
+ .get("/table/add-constraint/" + id + "/Unique")
202
204
  .set("Cookie", loginCookie)
203
205
  .expect(toInclude("Add constraint to books"));
204
206
  await request(app)
205
- .post("/table/add-constraint/" + id)
207
+ .post("/table/add-constraint/" + id + "/Unique")
206
208
  .send("author=on")
207
209
  .send("pages=on")
208
210
  .set("Cookie", loginCookie)
@@ -262,7 +264,22 @@ describe("deletion to table with row ownership", () => {
262
264
  const row = await persons.insertRow({ name: "something", owner: user.id });
263
265
  expect(await persons.countRows()).toBe(1);
264
266
  const loginCookie = await getStaffLoginCookie();
267
+ const uloginCookie = await getUserLoginCookie();
265
268
  const app = await getApp({ disableCsrf: true });
269
+ await request(app).get("/api/owned").expect(401);
270
+ await request(app)
271
+ .get("/api/owned")
272
+ .set("Cookie", loginCookie)
273
+ .expect(
274
+ succeedJsonWith(
275
+ (rows) => rows.length == 1 && rows[0].name === "something"
276
+ )
277
+ );
278
+ await request(app)
279
+ .get("/api/owned")
280
+ .set("Cookie", uloginCookie)
281
+ .expect(succeedJsonWith((rows) => rows.length == 0));
282
+
266
283
  await request(app)
267
284
  .post("/delete/owned/" + row)
268
285
  .expect(toRedirect("/list/owned"));
package/wrapper.js CHANGED
@@ -58,10 +58,22 @@ const get_menu = (req) => {
58
58
  ]
59
59
  : [
60
60
  ...(allow_signup
61
- ? [{ link: "/auth/signup", label: req.__("Sign up") }]
61
+ ? [
62
+ {
63
+ link: "/auth/signup",
64
+ icon: "fas fa-user-plus",
65
+ label: req.__("Sign up"),
66
+ },
67
+ ]
62
68
  : []),
63
69
  ...(login_menu
64
- ? [{ link: "/auth/login", label: req.__("Login") }]
70
+ ? [
71
+ {
72
+ link: "/auth/login",
73
+ icon: "fas fa-sign-in-alt",
74
+ label: req.__("Login"),
75
+ },
76
+ ]
65
77
  : []),
66
78
  ];
67
79
  // const schema = db.getTenantSchema();