@saltcorn/server 0.8.5-beta.3 → 0.8.5-beta.5

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
@@ -241,13 +241,16 @@ router.get(
241
241
  for (const f of fields) {
242
242
  if (f.type === "File") f.attributes = { select_file_where: {} };
243
243
  await f.fill_fkey_options();
244
+
245
+ if (f.type === "File") {
246
+ //add existing values in folders
247
+ const dvs = await f.distinct_values();
248
+ dvs.forEach((dv) => {
249
+ if (dv?.value?.includes("/")) f.options.push(dv);
250
+ });
251
+ }
244
252
  }
245
253
 
246
- //console.log(fields);
247
- // todo remove keyfields - unused
248
- const keyfields = fields
249
- .filter((f) => f.type === "Key" || f.type === "File")
250
- .map((f) => ({ name: f.name, type: f.reftype }));
251
254
  const jsfields = arrangeIdFirst(fields).map((f) =>
252
255
  typeToGridType(f.type, f)
253
256
  );
@@ -0,0 +1,136 @@
1
+ /**
2
+ * @category server
3
+ * @module routes/notifications
4
+ * @subcategory routes
5
+ */
6
+
7
+ const Router = require("express-promise-router");
8
+ const { isAdmin, setTenant, error_catcher, loggedIn } = require("./utils.js");
9
+ const Notification = require("@saltcorn/data/models/notification");
10
+ const { div, a, i, text, h5, p, span } = require("@saltcorn/markup/tags");
11
+ const moment = require("moment");
12
+ const { getState } = require("@saltcorn/data/db/state");
13
+ const Form = require("@saltcorn/data/models/form");
14
+ const User = require("@saltcorn/data/models/user");
15
+ const { renderForm } = require("@saltcorn/markup");
16
+
17
+ const router = new Router();
18
+ module.exports = router;
19
+
20
+ const notificationSettingsForm = () =>
21
+ new Form({
22
+ action: `/notifications/settings`,
23
+ noSubmitButton: true,
24
+ onChange: `saveAndContinue(this)`,
25
+ labelCols: 4,
26
+ fields: [{ name: "notify_email", label: "Email", type: "Bool" }],
27
+ });
28
+
29
+ router.get(
30
+ "/",
31
+ loggedIn,
32
+ error_catcher(async (req, res) => {
33
+ const nots = await Notification.find(
34
+ { user_id: req.user.id },
35
+ { orderBy: "id", orderDesc: true, limit: 20 }
36
+ );
37
+ await Notification.mark_as_read({
38
+ id: { in: nots.filter((n) => !n.read).map((n) => n.id) },
39
+ });
40
+ const notifyCards = nots.length
41
+ ? nots.map((not) => ({
42
+ type: "card",
43
+ class: [!not.read && "unread-notify"],
44
+ contents: [
45
+ div(
46
+ { class: "d-flex" },
47
+ span({ class: "fw-bold" }, not.title),
48
+ span({ class: "ms-2 text-muted" }, moment(not.created).fromNow())
49
+ ),
50
+ not.body && p(not.body),
51
+ not.link && a({ href: not.link }, "Link"),
52
+ ],
53
+ }))
54
+ : [
55
+ {
56
+ type: "card",
57
+ contents: [h5(req.__("No notifications"))],
58
+ },
59
+ ];
60
+ res.sendWrap(req.__("Notifications"), {
61
+ above: [
62
+ {
63
+ type: "breadcrumbs",
64
+ crumbs: [{ text: req.__("Notifications") }],
65
+ },
66
+ {
67
+ widths: [4, 8],
68
+ breakpoint: "md",
69
+ besides: [
70
+ {
71
+ type: "card",
72
+ contents: [
73
+ "Receive notifications by:",
74
+ renderForm(notificationSettingsForm(), req.csrfToken()),
75
+ ],
76
+ },
77
+ { above: notifyCards },
78
+ ],
79
+ },
80
+ ],
81
+ });
82
+ })
83
+ );
84
+
85
+ router.get(
86
+ "/count-unread",
87
+ loggedIn,
88
+ error_catcher(async (req, res) => {
89
+ const num_unread = await Notification.count({
90
+ user_id: req.user.id,
91
+ read: false,
92
+ });
93
+ res.set("Cache-Control", "public, max-age=60"); // 1 minute
94
+ res.json({ success: num_unread });
95
+ })
96
+ );
97
+
98
+ router.post(
99
+ "/settings",
100
+ loggedIn,
101
+ error_catcher(async (req, res) => {
102
+ const user = await User.findOne({ id: req.user.id });
103
+ const form = notificationSettingsForm();
104
+ form.validate(req.body);
105
+ const _attributes = { ...user._attributes, ...form.values };
106
+ await user.update({ _attributes });
107
+ res.json({ success: "ok" });
108
+ })
109
+ );
110
+
111
+ router.get(
112
+ "/manifest.json",
113
+ error_catcher(async (req, res) => {
114
+ const state = getState();
115
+ const manifest = {
116
+ name: state.getConfig("site_name"),
117
+ start_url: state.getConfig("base_url") || "/",
118
+ display: state.getConfig("pwa_display", "browser"),
119
+ };
120
+ const site_logo = state.getConfig("site_logo_id");
121
+ if (site_logo)
122
+ manifest.icons = [
123
+ {
124
+ src: `/files/serve/${site_logo}`,
125
+ },
126
+ ];
127
+ if (state.getConfig("pwa_set_colors", false)) {
128
+ manifest.theme_color = state.getConfig("pwa_theme_color", "black");
129
+ manifest.background_color = state.getConfig(
130
+ "pwa_background_color",
131
+ "red"
132
+ );
133
+ }
134
+ res.json(manifest);
135
+ })
136
+ );
package/routes/plugins.js CHANGED
@@ -14,11 +14,18 @@ const {
14
14
  post_btn,
15
15
  post_delete_btn,
16
16
  } = require("@saltcorn/markup");
17
- const { getState, restart_tenant } = require("@saltcorn/data/db/state");
17
+ const {
18
+ getState,
19
+ restart_tenant,
20
+ getRootState,
21
+ } = require("@saltcorn/data/db/state");
18
22
  const Form = require("@saltcorn/data/models/form");
19
23
  const Field = require("@saltcorn/data/models/field");
20
24
  const Plugin = require("@saltcorn/data/models/plugin");
21
25
  const { fetch_available_packs } = require("@saltcorn/admin-models/models/pack");
26
+ const {
27
+ upgrade_all_tenants_plugins,
28
+ } = require("@saltcorn/admin-models/models/tenant");
22
29
  const { getConfig, setConfig } = require("@saltcorn/data/models/config");
23
30
  const db = require("@saltcorn/data/db");
24
31
  const {
@@ -150,7 +157,10 @@ const local_has_theme = (name) => {
150
157
  const get_store_items = async () => {
151
158
  const installed_plugins = await Plugin.find({});
152
159
  const isRoot = db.getTenantSchema() === db.connectObj.default_schema;
153
-
160
+ const tenants_unsafe_plugins = getRootState().getConfig(
161
+ "tenants_unsafe_plugins",
162
+ false
163
+ );
154
164
  const instore = await Plugin.store_plugins_available();
155
165
  const packs_available = await fetch_available_packs();
156
166
  const packs_installed = getState().getConfig("installed_packs", []);
@@ -168,7 +178,7 @@ const get_store_items = async () => {
168
178
  has_auth: plugin.has_auth,
169
179
  unsafe: plugin.unsafe,
170
180
  }))
171
- .filter((p) => !p.unsafe || isRoot);
181
+ .filter((p) => !p.unsafe || isRoot || tenants_unsafe_plugins);
172
182
  const local_logins = installed_plugins
173
183
  .filter((p) => !store_plugin_names.includes(p.name) && p.name !== "base")
174
184
  .map((plugin) => ({
@@ -424,8 +434,12 @@ const filter_items_set = (items, query) => {
424
434
  * @param {object} req
425
435
  * @returns {div}
426
436
  */
427
- const store_actions_dropdown = (req) =>
428
- div(
437
+ const store_actions_dropdown = (req) => {
438
+ const tenants_install_git = getRootState().getConfig(
439
+ "tenants_install_git",
440
+ false
441
+ );
442
+ return div(
429
443
  { class: "dropdown" },
430
444
  button(
431
445
  {
@@ -460,7 +474,8 @@ const store_actions_dropdown = (req) =>
460
474
  '<i class="far fa-arrow-alt-circle-up"></i>&nbsp;' +
461
475
  req.__("Upgrade installed modules")
462
476
  ),
463
- db.getTenantSchema() === db.connectObj.default_schema &&
477
+ (db.getTenantSchema() === db.connectObj.default_schema ||
478
+ tenants_install_git) &&
464
479
  a(
465
480
  {
466
481
  class: "dropdown-item",
@@ -488,6 +503,7 @@ const store_actions_dropdown = (req) =>
488
503
  //create pack
489
504
  )
490
505
  );
506
+ };
491
507
 
492
508
  /**
493
509
  * @param {object[]} items
@@ -926,14 +942,22 @@ router.get(
926
942
  "/upgrade",
927
943
  isAdmin,
928
944
  error_catcher(async (req, res) => {
929
- const installed_plugins = await Plugin.find({});
930
- for (const plugin of installed_plugins) {
931
- await plugin.upgrade_version((p, f) => load_plugins.loadPlugin(p, f));
945
+ const schema = db.getTenantSchema();
946
+ if (schema === db.connectObj.default_schema) {
947
+ await upgrade_all_tenants_plugins((p, f) =>
948
+ load_plugins.loadPlugin(p, f)
949
+ );
950
+ req.flash("success", req.__(`Modules up-to-date. Please restart server`));
951
+ } else {
952
+ const installed_plugins = await Plugin.find({});
953
+ for (const plugin of installed_plugins) {
954
+ await plugin.upgrade_version((p, f) => load_plugins.loadPlugin(p, f));
955
+ }
956
+ req.flash("success", req.__(`Modules up-to-date`));
957
+ await restart_tenant(loadAllPlugins);
958
+ process.send &&
959
+ process.send({ restart_tenant: true, tenant: db.getTenantSchema() });
932
960
  }
933
- req.flash("success", req.__(`Modules up-to-date`));
934
- await restart_tenant(loadAllPlugins);
935
- process.send &&
936
- process.send({ restart_tenant: true, tenant: db.getTenantSchema() });
937
961
  res.redirect(`/plugins`);
938
962
  })
939
963
  );
@@ -970,7 +994,11 @@ router.post(
970
994
  error_catcher(async (req, res) => {
971
995
  const plugin = new Plugin(req.body);
972
996
  const schema = db.getTenantSchema();
973
- if (schema !== db.connectObj.default_schema) {
997
+ const tenants_install_git = getRootState().getConfig(
998
+ "tenants_install_git",
999
+ false
1000
+ );
1001
+ if (schema !== db.connectObj.default_schema && !tenants_install_git) {
974
1002
  req.flash(
975
1003
  "error",
976
1004
  req.__(`Only store modules can be installed on tenant instances`)
@@ -1039,7 +1067,10 @@ router.post(
1039
1067
  isAdmin,
1040
1068
  error_catcher(async (req, res) => {
1041
1069
  const { name } = req.params;
1042
-
1070
+ const tenants_unsafe_plugins = getRootState().getConfig(
1071
+ "tenants_unsafe_plugins",
1072
+ false
1073
+ );
1043
1074
  const plugin = await Plugin.store_by_name(decodeURIComponent(name));
1044
1075
  if (!plugin) {
1045
1076
  req.flash(
@@ -1050,7 +1081,7 @@ router.post(
1050
1081
  return;
1051
1082
  }
1052
1083
  const isRoot = db.getTenantSchema() === db.connectObj.default_schema;
1053
- if (!isRoot && plugin.unsafe) {
1084
+ if (!isRoot && plugin.unsafe && !tenants_unsafe_plugins) {
1054
1085
  req.flash(
1055
1086
  "error",
1056
1087
  req.__("Cannot install unsafe modules on subdomain tenants")
package/routes/tables.js CHANGED
@@ -51,6 +51,7 @@ const {
51
51
  const { getState } = require("@saltcorn/data/db/state");
52
52
  const { cardHeaderTabs } = require("@saltcorn/markup/layout_utils");
53
53
  const { tablesList } = require("./common_lists");
54
+ const { InvalidConfiguration } = require("@saltcorn/data/utils");
54
55
 
55
56
  /**
56
57
  * @type {object}
@@ -180,6 +181,7 @@ router.get(
180
181
  "/new/",
181
182
  isAdmin,
182
183
  error_catcher(async (req, res) => {
184
+ const table_provider_names = Object.keys(getState().table_providers);
183
185
  res.sendWrap(req.__(`New table`), {
184
186
  above: [
185
187
  {
@@ -203,6 +205,20 @@ router.get(
203
205
  input_type: "text",
204
206
  required: true,
205
207
  },
208
+ ...(table_provider_names.length
209
+ ? [
210
+ {
211
+ label: req.__("Table provider"),
212
+ name: "provider_name",
213
+ input_type: "select",
214
+ options: [
215
+ req.__("Database table"),
216
+ ...table_provider_names,
217
+ ],
218
+ required: true,
219
+ },
220
+ ]
221
+ : []),
206
222
  ],
207
223
  }),
208
224
  req.csrfToken()
@@ -439,8 +455,7 @@ router.get(
439
455
  title: req.__("Tables"),
440
456
  headers: [
441
457
  {
442
- script:
443
- "https://unpkg.com/vis-network@9.1.2/standalone/umd/vis-network.min.js",
458
+ script: `/static_assets/${db.connectObj.version_tag}/vis-network.min.js`,
444
459
  },
445
460
  ],
446
461
  },
@@ -549,9 +564,9 @@ router.get(
549
564
  const { idorname } = req.params;
550
565
  let id = parseInt(idorname);
551
566
  let table;
552
- if (id) table = await Table.findOne({ id });
567
+ if (id) table = Table.findOne({ id });
553
568
  else {
554
- table = await Table.findOne({ name: idorname });
569
+ table = Table.findOne({ name: idorname });
555
570
  }
556
571
 
557
572
  if (!table) {
@@ -646,7 +661,7 @@ router.get(
646
661
  var viewCard;
647
662
  if (fields.length > 0) {
648
663
  const views = await View.find(
649
- table.external ? { exttable_name: table.name } : { table_id: table.id }
664
+ table.id ? { table_id: table.id } : { exttable_name: table.name }
650
665
  );
651
666
  var viewCardContents;
652
667
  if (views.length > 0) {
@@ -727,6 +742,16 @@ router.get(
727
742
  : req.__("Edit")
728
743
  )
729
744
  ),
745
+ table.provider_name &&
746
+ div(
747
+ { class: "mx-auto" },
748
+ a(
749
+ { href: `/table/provider-cfg/${table.id}` },
750
+ i({ class: "fas fa-2x fa-tools" }),
751
+ "<br/>",
752
+ req.__("Configure provider")
753
+ )
754
+ ),
730
755
  div(
731
756
  { class: "mx-auto" },
732
757
  a(
@@ -821,7 +846,13 @@ router.get(
821
846
  type: "breadcrumbs",
822
847
  crumbs: [
823
848
  { text: req.__("Tables"), href: "/table" },
824
- { text: span({ class: "fw-bold text-body" }, table.name) },
849
+ {
850
+ text: span(
851
+ { class: "fw-bold text-body" },
852
+ table.name,
853
+ table.provider_name && ` (${table.provider_name} provider)`
854
+ ),
855
+ },
825
856
  ],
826
857
  },
827
858
  {
@@ -876,7 +907,14 @@ router.post(
876
907
  } else if (db.sqlsanitize(name) === "") {
877
908
  req.flash("error", req.__(`Invalid table name %s`, name));
878
909
  res.redirect(`/table/new`);
910
+ } else if (
911
+ rest.provider_name &&
912
+ rest.provider_name !== "Database table"
913
+ ) {
914
+ const table = await Table.create(name, rest);
915
+ res.redirect(`/table/provider-cfg/${table.id}`);
879
916
  } else {
917
+ delete rest.provider_name;
880
918
  const table = await Table.create(name, rest);
881
919
  req.flash("success", req.__(`Table %s created`, name));
882
920
  res.redirect(`/table/${table.id}`);
@@ -1005,23 +1043,6 @@ router.post(
1005
1043
  }
1006
1044
  })
1007
1045
  );
1008
- /**
1009
- * Table badges to show in System Table list views
1010
- * Currently supports:
1011
- * - Owned - if ownership_field_id? What is it?
1012
- * - History - if table has versioning
1013
- * - External - if this is external table
1014
- * @param {object} t table object
1015
- * @param {object} req http request
1016
- * @returns {string} html string with list of badges
1017
- */
1018
- const tableBadges = (t, req) => {
1019
- let s = "";
1020
- if (t.ownership_field_id) s += badge("primary", req.__("Owned"));
1021
- if (t.versioned) s += badge("success", req.__("History"));
1022
- if (t.external) s += badge("info", req.__("External"));
1023
- return s;
1024
- };
1025
1046
 
1026
1047
  /**
1027
1048
  * List Views of Tables (GET Handler)
@@ -1529,3 +1550,119 @@ router.post(
1529
1550
  res.redirect(`/table/${table.id}`);
1530
1551
  })
1531
1552
  );
1553
+
1554
+ const respondWorkflow = (table, wf, wfres, req, res) => {
1555
+ const wrap = (contents, noCard, previewURL) => ({
1556
+ above: [
1557
+ {
1558
+ type: "breadcrumbs",
1559
+ crumbs: [
1560
+ { text: req.__("Tables"), href: "/table" },
1561
+ { href: `/table/${table.id || table.name}`, text: table.name },
1562
+ { text: req.__("Configuration") },
1563
+ ],
1564
+ },
1565
+ {
1566
+ type: noCard ? "container" : "card",
1567
+ class: !noCard && "mt-0",
1568
+ title: wfres.title,
1569
+ titleAjaxIndicator: true,
1570
+ contents,
1571
+ },
1572
+ ],
1573
+ });
1574
+ if (wfres.flash) req.flash(wfres.flash[0], wfres.flash[1]);
1575
+ if (wfres.renderForm)
1576
+ res.sendWrap(
1577
+ {
1578
+ title: req.__(`%s configuration`, table.name),
1579
+ headers: [
1580
+ {
1581
+ script: `/static_assets/${db.connectObj.version_tag}/jquery-menu-editor.min.js`,
1582
+ },
1583
+ {
1584
+ script: `/static_assets/${db.connectObj.version_tag}/iconset-fontawesome5-3-1.min.js`,
1585
+ },
1586
+ {
1587
+ script: `/static_assets/${db.connectObj.version_tag}/bootstrap-iconpicker.js`,
1588
+ },
1589
+ {
1590
+ css: `/static_assets/${db.connectObj.version_tag}/bootstrap-iconpicker.min.css`,
1591
+ },
1592
+ ],
1593
+ },
1594
+ wrap(
1595
+ renderForm(wfres.renderForm, req.csrfToken()),
1596
+ false,
1597
+ wfres.previewURL
1598
+ )
1599
+ );
1600
+ else res.redirect(wfres.redirect);
1601
+ };
1602
+
1603
+ const get_provider_workflow = (table, req) => {
1604
+ const provider = getState().table_providers[table.provider_name];
1605
+ if (!provider) {
1606
+ throw new InvalidConfiguration(
1607
+ `Provider not found for rable ${table.name}: table.provider_name`
1608
+ );
1609
+ }
1610
+ const workflow = provider.configuration_workflow(req);
1611
+ workflow.action = `/table/provider-cfg/${table.id}`;
1612
+ const oldOnDone = workflow.onDone || ((c) => c);
1613
+ workflow.onDone = async (ctx) => {
1614
+ const { table_id, ...configuration } = await oldOnDone(ctx);
1615
+ await table.update({ provider_cfg: configuration });
1616
+
1617
+ return {
1618
+ redirect: `/table/${table.id}`,
1619
+ flash: ["success", `Table ${this.name || ""} saved`],
1620
+ };
1621
+ };
1622
+ return workflow;
1623
+ };
1624
+
1625
+ router.get(
1626
+ "/provider-cfg/:id",
1627
+ isAdmin,
1628
+ error_catcher(async (req, res) => {
1629
+ const { id } = req.params;
1630
+ const { step } = req.query;
1631
+
1632
+ const table = await Table.findOne({ id });
1633
+ if (!table) {
1634
+ req.flash("error", `Table not found`);
1635
+ res.redirect(`/table`);
1636
+ return;
1637
+ }
1638
+ const workflow = get_provider_workflow(table, req);
1639
+ const wfres = await workflow.run(
1640
+ {
1641
+ ...(table.provider_cfg || {}),
1642
+ table_id: table.id,
1643
+ ...(step ? { stepName: step } : {}),
1644
+ },
1645
+ req
1646
+ );
1647
+ respondWorkflow(table, workflow, wfres, req, res);
1648
+ })
1649
+ );
1650
+
1651
+ router.post(
1652
+ "/provider-cfg/:id",
1653
+ isAdmin,
1654
+ error_catcher(async (req, res) => {
1655
+ const { id } = req.params;
1656
+ const { step } = req.query;
1657
+
1658
+ const table = await Table.findOne({ id });
1659
+ if (!table) {
1660
+ req.flash("error", `Table not found`);
1661
+ res.redirect(`/table`);
1662
+ return;
1663
+ }
1664
+ const workflow = get_provider_workflow(table, req);
1665
+ const wfres = await workflow.run(req.body, req);
1666
+ respondWorkflow(table, workflow, wfres, req, res);
1667
+ })
1668
+ );
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
@@ -19,7 +19,12 @@ const is = require("contractis/is");
19
19
  const { validateHeaderName, validateHeaderValue } = require("http");
20
20
  const Crash = require("@saltcorn/data/models/crash");
21
21
  const si = require("systeminformation");
22
-
22
+ const {
23
+ config_fields_form,
24
+ save_config_from_form,
25
+ check_if_restart_required,
26
+ flash_restart,
27
+ } = require("../markup/admin.js");
23
28
  const get_sys_info = async () => {
24
29
  const disks = await si.fsSize();
25
30
  let size = 0;
@@ -318,6 +323,63 @@ const is_relative_url = (url) => {
318
323
  return typeof url === "string" && !url.includes(":/") && !url.includes("//");
319
324
  };
320
325
 
326
+ const admin_config_route = ({
327
+ router,
328
+ path,
329
+ super_path = "",
330
+ get_form,
331
+ field_names,
332
+ response,
333
+ flash,
334
+ }) => {
335
+ const getTheForm = async (req) =>
336
+ !get_form && field_names
337
+ ? await config_fields_form({
338
+ req,
339
+ field_names,
340
+ action: super_path + path,
341
+ })
342
+ : typeof get_form === "function"
343
+ ? await get_form(req)
344
+ : get_form;
345
+
346
+ router.get(
347
+ path,
348
+ isAdmin,
349
+ error_catcher(async (req, res) => {
350
+ response(await getTheForm(req), req, res);
351
+ })
352
+ );
353
+ router.post(
354
+ path,
355
+ isAdmin,
356
+ error_catcher(async (req, res) => {
357
+ const form = await getTheForm(req);
358
+ form.validate(req.body);
359
+ if (form.hasErrors) {
360
+ response(form, req, res);
361
+ } else {
362
+ const restart_required = check_if_restart_required(form, req);
363
+
364
+ await save_config_from_form(form);
365
+ if (!req.xhr) {
366
+ if (restart_required) {
367
+ flash_restart(req);
368
+ } else req.flash("success", req.__(flash));
369
+ res.redirect(super_path + path);
370
+ } else {
371
+ if (restart_required)
372
+ res.json({
373
+ success: "ok",
374
+ notify: req.__("Restart required for changes to take effect."),
375
+ });
376
+ else res.json({ success: "ok" });
377
+ }
378
+ }
379
+ })
380
+ );
381
+ };
382
+
321
383
  module.exports = {
322
384
  sqlsanitize,
323
385
  csrfField,
@@ -333,4 +395,5 @@ module.exports = {
333
395
  addOnDoneRedirect,
334
396
  is_relative_url,
335
397
  get_sys_info,
398
+ admin_config_route,
336
399
  };
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")