@saltcorn/server 0.8.8-beta.1 → 0.8.8-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/load_plugins.js +8 -1
- package/locales/en.json +6 -1
- package/locales/ru.json +4 -1
- package/package.json +8 -8
- package/public/saltcorn.js +44 -1
- package/routes/admin.js +98 -2
- package/routes/fields.js +0 -8
- package/routes/scapi.js +1 -1
- package/routes/sync.js +293 -57
- package/routes/tables.js +19 -1
- package/tests/plugin_install.test.js +114 -0
- package/tests/plugins.test.js +2 -102
- package/tests/sync.test.js +451 -75
- package/tests/view.test.js +2 -0
- package/tests/viewedit.test.js +2 -0
- package/wrapper.js +6 -4
package/routes/tables.js
CHANGED
|
@@ -168,6 +168,19 @@ const tableForm = async (table, req) => {
|
|
|
168
168
|
name: "versioned",
|
|
169
169
|
type: "Bool",
|
|
170
170
|
},
|
|
171
|
+
...(table.name === "users"
|
|
172
|
+
? []
|
|
173
|
+
: [
|
|
174
|
+
{
|
|
175
|
+
label: req.__("Sync information"),
|
|
176
|
+
sublabel: req.__(
|
|
177
|
+
"Sync information tracks the last modification or deletion timestamp " +
|
|
178
|
+
"so that the table data can be synchronized with the mobile app"
|
|
179
|
+
),
|
|
180
|
+
name: "has_sync_info",
|
|
181
|
+
type: "Bool",
|
|
182
|
+
},
|
|
183
|
+
]),
|
|
171
184
|
]),
|
|
172
185
|
],
|
|
173
186
|
});
|
|
@@ -922,7 +935,10 @@ router.get(
|
|
|
922
935
|
{ href: `/table/constraints/${table.id}` },
|
|
923
936
|
i({ class: "fas fa-2x fa-tasks" }),
|
|
924
937
|
"<br/>",
|
|
925
|
-
req.__("Constraints")
|
|
938
|
+
req.__("Constraints") +
|
|
939
|
+
(table.constraints?.length
|
|
940
|
+
? ` (${table.constraints.length})`
|
|
941
|
+
: "")
|
|
926
942
|
)
|
|
927
943
|
),
|
|
928
944
|
|
|
@@ -1080,9 +1096,11 @@ router.post(
|
|
|
1080
1096
|
const { id, _csrf, ...rest } = v;
|
|
1081
1097
|
const table = Table.findOne({ id: parseInt(id) });
|
|
1082
1098
|
const old_versioned = table.versioned;
|
|
1099
|
+
const old_has_sync_info = table.has_sync_info;
|
|
1083
1100
|
let hasError = false;
|
|
1084
1101
|
let notify = "";
|
|
1085
1102
|
if (!rest.versioned) rest.versioned = false;
|
|
1103
|
+
if (!rest.has_sync_info) rest.has_sync_info = false;
|
|
1086
1104
|
if (rest.ownership_field_id === "_formula") {
|
|
1087
1105
|
rest.ownership_field_id = null;
|
|
1088
1106
|
const fmlValidRes = expressionValidator(rest.ownership_formula);
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
const Table = require("@saltcorn/data/models/table");
|
|
2
|
+
const Plugin = require("@saltcorn/data/models/plugin");
|
|
3
|
+
const { getState, add_tenant } = require("@saltcorn/data/db/state");
|
|
4
|
+
const { install_pack } = require("@saltcorn/admin-models/models/pack");
|
|
5
|
+
const {
|
|
6
|
+
switchToTenant,
|
|
7
|
+
insertTenant,
|
|
8
|
+
create_tenant,
|
|
9
|
+
} = require("@saltcorn/admin-models/models/tenant");
|
|
10
|
+
const { resetToFixtures } = require("../auth/testhelp");
|
|
11
|
+
const db = require("@saltcorn/data/db");
|
|
12
|
+
const load_plugins = require("../load_plugins");
|
|
13
|
+
|
|
14
|
+
beforeAll(async () => {
|
|
15
|
+
if (!db.isSQLite) await db.query(`drop schema if exists test101 CASCADE `);
|
|
16
|
+
await resetToFixtures();
|
|
17
|
+
});
|
|
18
|
+
afterAll(db.close);
|
|
19
|
+
|
|
20
|
+
jest.setTimeout(30000);
|
|
21
|
+
const plugin_pack = (plugin) => ({
|
|
22
|
+
tables: [],
|
|
23
|
+
views: [],
|
|
24
|
+
plugins: [
|
|
25
|
+
{
|
|
26
|
+
...plugin,
|
|
27
|
+
configuration: null,
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
pages: [],
|
|
31
|
+
roles: [],
|
|
32
|
+
library: [],
|
|
33
|
+
triggers: [],
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
describe("Tenant cannot install unsafe plugins", () => {
|
|
37
|
+
if (!db.isSQLite) {
|
|
38
|
+
it("creates a new tenant", async () => {
|
|
39
|
+
db.enable_multi_tenant();
|
|
40
|
+
const loadAndSaveNewPlugin = load_plugins.loadAndSaveNewPlugin;
|
|
41
|
+
|
|
42
|
+
await getState().setConfig("base_url", "http://example.com/");
|
|
43
|
+
|
|
44
|
+
add_tenant("test101");
|
|
45
|
+
|
|
46
|
+
await switchToTenant(
|
|
47
|
+
await insertTenant("test101", "foo@foo.com", ""),
|
|
48
|
+
"http://test101.example.com/"
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
await create_tenant({
|
|
52
|
+
t: "test101",
|
|
53
|
+
loadAndSaveNewPlugin,
|
|
54
|
+
plugin_loader() {},
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
it("can install safe plugins on tenant", async () => {
|
|
58
|
+
await db.runWithTenant("test101", async () => {
|
|
59
|
+
const loadAndSaveNewPlugin = load_plugins.loadAndSaveNewPlugin;
|
|
60
|
+
|
|
61
|
+
await install_pack(
|
|
62
|
+
plugin_pack({
|
|
63
|
+
name: "html",
|
|
64
|
+
source: "npm",
|
|
65
|
+
location: "@saltcorn/html",
|
|
66
|
+
}),
|
|
67
|
+
"Todo list",
|
|
68
|
+
loadAndSaveNewPlugin
|
|
69
|
+
);
|
|
70
|
+
const dbPlugin = await Plugin.findOne({ name: "html" });
|
|
71
|
+
expect(dbPlugin).not.toBe(null);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
it("cannot install unsafe plugins on tenant", async () => {
|
|
75
|
+
await db.runWithTenant("test101", async () => {
|
|
76
|
+
const loadAndSaveNewPlugin = load_plugins.loadAndSaveNewPlugin;
|
|
77
|
+
|
|
78
|
+
await install_pack(
|
|
79
|
+
plugin_pack({
|
|
80
|
+
name: "sql-list",
|
|
81
|
+
source: "npm",
|
|
82
|
+
location: "@saltcorn/sql-list",
|
|
83
|
+
}),
|
|
84
|
+
"Todo list",
|
|
85
|
+
loadAndSaveNewPlugin
|
|
86
|
+
);
|
|
87
|
+
const dbPlugin = await Plugin.findOne({ name: "sql-list" });
|
|
88
|
+
expect(dbPlugin).toBe(null);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
it("can install unsafe plugins on tenant when permitted", async () => {
|
|
92
|
+
await getState().setConfig("tenants_unsafe_plugins", true);
|
|
93
|
+
await db.runWithTenant("test101", async () => {
|
|
94
|
+
const loadAndSaveNewPlugin = load_plugins.loadAndSaveNewPlugin;
|
|
95
|
+
|
|
96
|
+
await install_pack(
|
|
97
|
+
plugin_pack({
|
|
98
|
+
name: "sql-list",
|
|
99
|
+
source: "npm",
|
|
100
|
+
location: "@saltcorn/sql-list",
|
|
101
|
+
}),
|
|
102
|
+
"Todo list",
|
|
103
|
+
loadAndSaveNewPlugin
|
|
104
|
+
);
|
|
105
|
+
const dbPlugin = await Plugin.findOne({ name: "sql-list" });
|
|
106
|
+
expect(dbPlugin).not.toBe(null);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
} else {
|
|
110
|
+
it("does not support tenants on SQLite", async () => {
|
|
111
|
+
expect(db.isSQLite).toBe(true);
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
});
|
package/tests/plugins.test.js
CHANGED
|
@@ -2,13 +2,8 @@ const request = require("supertest");
|
|
|
2
2
|
const getApp = require("../app");
|
|
3
3
|
const Table = require("@saltcorn/data/models/table");
|
|
4
4
|
const Plugin = require("@saltcorn/data/models/plugin");
|
|
5
|
-
const { getState
|
|
6
|
-
|
|
7
|
-
const {
|
|
8
|
-
switchToTenant,
|
|
9
|
-
insertTenant,
|
|
10
|
-
create_tenant,
|
|
11
|
-
} = require("@saltcorn/admin-models/models/tenant");
|
|
5
|
+
const { getState } = require("@saltcorn/data/db/state");
|
|
6
|
+
|
|
12
7
|
const {
|
|
13
8
|
getAdminLoginCookie,
|
|
14
9
|
itShouldRedirectUnauthToLogin,
|
|
@@ -331,98 +326,3 @@ describe("config endpoints", () => {
|
|
|
331
326
|
.expect(toInclude(">FooSiteName<"));
|
|
332
327
|
});
|
|
333
328
|
});
|
|
334
|
-
|
|
335
|
-
const plugin_pack = (plugin) => ({
|
|
336
|
-
tables: [],
|
|
337
|
-
views: [],
|
|
338
|
-
plugins: [
|
|
339
|
-
{
|
|
340
|
-
...plugin,
|
|
341
|
-
configuration: null,
|
|
342
|
-
},
|
|
343
|
-
],
|
|
344
|
-
pages: [],
|
|
345
|
-
roles: [],
|
|
346
|
-
library: [],
|
|
347
|
-
triggers: [],
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
describe("Tenant cannot install unsafe plugins", () => {
|
|
351
|
-
if (!db.isSQLite) {
|
|
352
|
-
it("creates a new tenant", async () => {
|
|
353
|
-
db.enable_multi_tenant();
|
|
354
|
-
const loadAndSaveNewPlugin = load_plugins.loadAndSaveNewPlugin;
|
|
355
|
-
|
|
356
|
-
await getState().setConfig("base_url", "http://example.com/");
|
|
357
|
-
|
|
358
|
-
add_tenant("test101");
|
|
359
|
-
|
|
360
|
-
await switchToTenant(
|
|
361
|
-
await insertTenant("test101", "foo@foo.com", ""),
|
|
362
|
-
"http://test101.example.com/"
|
|
363
|
-
);
|
|
364
|
-
|
|
365
|
-
await create_tenant({
|
|
366
|
-
t: "test101",
|
|
367
|
-
loadAndSaveNewPlugin,
|
|
368
|
-
plugin_loader() {},
|
|
369
|
-
});
|
|
370
|
-
});
|
|
371
|
-
it("can install safe plugins on tenant", async () => {
|
|
372
|
-
await db.runWithTenant("test101", async () => {
|
|
373
|
-
const loadAndSaveNewPlugin = load_plugins.loadAndSaveNewPlugin;
|
|
374
|
-
|
|
375
|
-
await install_pack(
|
|
376
|
-
plugin_pack({
|
|
377
|
-
name: "html",
|
|
378
|
-
source: "npm",
|
|
379
|
-
location: "@saltcorn/html",
|
|
380
|
-
}),
|
|
381
|
-
"Todo list",
|
|
382
|
-
loadAndSaveNewPlugin
|
|
383
|
-
);
|
|
384
|
-
const dbPlugin = await Plugin.findOne({ name: "html" });
|
|
385
|
-
expect(dbPlugin).not.toBe(null);
|
|
386
|
-
});
|
|
387
|
-
});
|
|
388
|
-
it("cannot install unsafe plugins on tenant", async () => {
|
|
389
|
-
await db.runWithTenant("test101", async () => {
|
|
390
|
-
const loadAndSaveNewPlugin = load_plugins.loadAndSaveNewPlugin;
|
|
391
|
-
|
|
392
|
-
await install_pack(
|
|
393
|
-
plugin_pack({
|
|
394
|
-
name: "sql-list",
|
|
395
|
-
source: "npm",
|
|
396
|
-
location: "@saltcorn/sql-list",
|
|
397
|
-
}),
|
|
398
|
-
"Todo list",
|
|
399
|
-
loadAndSaveNewPlugin
|
|
400
|
-
);
|
|
401
|
-
const dbPlugin = await Plugin.findOne({ name: "sql-list" });
|
|
402
|
-
expect(dbPlugin).toBe(null);
|
|
403
|
-
});
|
|
404
|
-
});
|
|
405
|
-
it("can install unsafe plugins on tenant when permitted", async () => {
|
|
406
|
-
await getState().setConfig("tenants_unsafe_plugins", true);
|
|
407
|
-
await db.runWithTenant("test101", async () => {
|
|
408
|
-
const loadAndSaveNewPlugin = load_plugins.loadAndSaveNewPlugin;
|
|
409
|
-
|
|
410
|
-
await install_pack(
|
|
411
|
-
plugin_pack({
|
|
412
|
-
name: "sql-list",
|
|
413
|
-
source: "npm",
|
|
414
|
-
location: "@saltcorn/sql-list",
|
|
415
|
-
}),
|
|
416
|
-
"Todo list",
|
|
417
|
-
loadAndSaveNewPlugin
|
|
418
|
-
);
|
|
419
|
-
const dbPlugin = await Plugin.findOne({ name: "sql-list" });
|
|
420
|
-
expect(dbPlugin).not.toBe(null);
|
|
421
|
-
});
|
|
422
|
-
});
|
|
423
|
-
} else {
|
|
424
|
-
it("does not support tenants on SQLite", async () => {
|
|
425
|
-
expect(db.isSQLite).toBe(true);
|
|
426
|
-
});
|
|
427
|
-
}
|
|
428
|
-
});
|