@saltcorn/server 1.0.0-beta.2 → 1.0.0-beta.3
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/help/Android App Signing.tmd +1 -1
- package/locales/en.json +6 -1
- package/markup/blockly.js +4 -4
- package/package.json +13 -13
- package/public/saltcorn-common.js +11 -3
- package/public/saltcorn.js +3 -0
- package/routes/admin.js +31 -0
- package/routes/files.js +101 -15
- package/routes/notifications.js +13 -3
- package/routes/viewedit.js +10 -2
- package/tests/files.test.js +87 -7
|
@@ -8,7 +8,7 @@ To build an Android app for the Play Store, you need to create an Android Applic
|
|
|
8
8
|
|
|
9
9
|
*Note: You need a [Play Console developer account](https://support.google.com/googleplay/android-developer/answer/6112435?hl=en&ref_topic=3450769&sjid=11090022771305927482-EU) to publish your app on the Play Store.*
|
|
10
10
|
|
|
11
|
-
### Create a
|
|
11
|
+
### Create a Keystore file
|
|
12
12
|
On any Unix-based system, you can use the `keytool` command to create the keystore file. For example:
|
|
13
13
|
```sh
|
|
14
14
|
keytool -genkey -v -keystore my-app-key.jks
|
package/locales/en.json
CHANGED
|
@@ -1459,5 +1459,10 @@
|
|
|
1459
1459
|
"Hourly": "Hourly",
|
|
1460
1460
|
"Daily": "Daily",
|
|
1461
1461
|
"Weekly": "Weekly",
|
|
1462
|
-
"Code pages": "Code pages"
|
|
1462
|
+
"Code pages": "Code pages",
|
|
1463
|
+
"Please select a file": "Please select a file",
|
|
1464
|
+
"Zip compression level": "Zip compression level",
|
|
1465
|
+
"1=Fast, larger file, 9=Slow, smaller files": "1=Fast, larger file, 9=Slow, smaller files",
|
|
1466
|
+
"Use system zip": "Use system zip",
|
|
1467
|
+
"Recommended. Executable <code>zip</code> must be installed": "Recommended. Executable <code>zip</code> must be installed"
|
|
1463
1468
|
}
|
package/markup/blockly.js
CHANGED
|
@@ -22,16 +22,16 @@ const db = require("@saltcorn/data/db");
|
|
|
22
22
|
*/
|
|
23
23
|
const blocklyImportScripts = ({ locale }) =>
|
|
24
24
|
script({
|
|
25
|
-
src: "/plugins/pubdeps/base/blockly/
|
|
25
|
+
src: "/plugins/pubdeps/base/blockly/8.0.5/blockly_compressed.js",
|
|
26
26
|
}) +
|
|
27
27
|
script({
|
|
28
|
-
src: "/plugins/pubdeps/base/blockly/
|
|
28
|
+
src: "/plugins/pubdeps/base/blockly/8.0.5/blocks_compressed.js",
|
|
29
29
|
}) +
|
|
30
30
|
script({
|
|
31
|
-
src: `/plugins/pubdeps/base/blockly/
|
|
31
|
+
src: `/plugins/pubdeps/base/blockly/8.0.5/msg/${locale}.js`,
|
|
32
32
|
}) +
|
|
33
33
|
script({
|
|
34
|
-
src: "/plugins/pubdeps/base/blockly/
|
|
34
|
+
src: "/plugins/pubdeps/base/blockly/8.0.5/javascript_compressed.js",
|
|
35
35
|
}) +
|
|
36
36
|
script({
|
|
37
37
|
src: `/static_assets/${db.connectObj.version_tag}/blockly.js`,
|
package/package.json
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saltcorn/server",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.3",
|
|
4
4
|
"description": "Server app for Saltcorn, open-source no-code platform",
|
|
5
5
|
"homepage": "https://saltcorn.com",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"@aws-sdk/client-s3": "^3.451.0",
|
|
10
|
-
"@saltcorn/base-plugin": "1.0.0-beta.
|
|
11
|
-
"@saltcorn/builder": "1.0.0-beta.
|
|
12
|
-
"@saltcorn/data": "1.0.0-beta.
|
|
13
|
-
"@saltcorn/admin-models": "1.0.0-beta.
|
|
14
|
-
"@saltcorn/filemanager": "1.0.0-beta.
|
|
15
|
-
"@saltcorn/markup": "1.0.0-beta.
|
|
16
|
-
"@saltcorn/plugins-loader": "1.0.0-beta.
|
|
17
|
-
"@saltcorn/sbadmin2": "1.0.0-beta.
|
|
10
|
+
"@saltcorn/base-plugin": "1.0.0-beta.3",
|
|
11
|
+
"@saltcorn/builder": "1.0.0-beta.3",
|
|
12
|
+
"@saltcorn/data": "1.0.0-beta.3",
|
|
13
|
+
"@saltcorn/admin-models": "1.0.0-beta.3",
|
|
14
|
+
"@saltcorn/filemanager": "1.0.0-beta.3",
|
|
15
|
+
"@saltcorn/markup": "1.0.0-beta.3",
|
|
16
|
+
"@saltcorn/plugins-loader": "1.0.0-beta.3",
|
|
17
|
+
"@saltcorn/sbadmin2": "1.0.0-beta.3",
|
|
18
18
|
"@socket.io/cluster-adapter": "^0.2.1",
|
|
19
19
|
"@socket.io/sticky": "^1.0.1",
|
|
20
20
|
"adm-zip": "0.5.10",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"tmp-promise": "^3.0.2",
|
|
64
64
|
"ua-parser-js": "^1.0.37",
|
|
65
65
|
"underscore": "1.13.6",
|
|
66
|
-
"uuid": "^
|
|
66
|
+
"uuid": "^10.0.0"
|
|
67
67
|
},
|
|
68
68
|
"optionalDependencies": {
|
|
69
69
|
"connect-sqlite3": "^0.9.11",
|
|
@@ -71,9 +71,9 @@
|
|
|
71
71
|
},
|
|
72
72
|
"repository": "github:saltcorn/saltcorn",
|
|
73
73
|
"devDependencies": {
|
|
74
|
-
"jest": "^
|
|
75
|
-
"jest-environment-jsdom": "
|
|
76
|
-
"supertest": "
|
|
74
|
+
"jest": "^29.7.0",
|
|
75
|
+
"jest-environment-jsdom": "29.7.0",
|
|
76
|
+
"supertest": "7.0.0"
|
|
77
77
|
},
|
|
78
78
|
"scripts": {
|
|
79
79
|
"dev": "nodemon index.js",
|
|
@@ -421,7 +421,14 @@ function apply_showif() {
|
|
|
421
421
|
navigator.systemLanguage ||
|
|
422
422
|
"en";
|
|
423
423
|
window.detected_locale = locale;
|
|
424
|
-
const parse = (s) =>
|
|
424
|
+
const parse = (s, def = {}) => {
|
|
425
|
+
try {
|
|
426
|
+
return JSON.parse(decodeURIComponent(s));
|
|
427
|
+
} catch (e) {
|
|
428
|
+
console.error("failed to parse time format", e);
|
|
429
|
+
return def;
|
|
430
|
+
}
|
|
431
|
+
};
|
|
425
432
|
$("time[locale-time-options]").each(function () {
|
|
426
433
|
var el = $(this);
|
|
427
434
|
var date = new Date(el.attr("datetime"));
|
|
@@ -443,8 +450,9 @@ function apply_showif() {
|
|
|
443
450
|
$("time[locale-date-format]").each(function () {
|
|
444
451
|
var el = $(this);
|
|
445
452
|
var date = el.attr("datetime");
|
|
446
|
-
const format = parse(el.attr("locale-date-format"));
|
|
447
|
-
el.text(dayjs(date).format(format));
|
|
453
|
+
const format = parse(el.attr("locale-date-format"), "");
|
|
454
|
+
if (format) el.text(dayjs(date).format(format));
|
|
455
|
+
else el.text(dayjs(date));
|
|
448
456
|
});
|
|
449
457
|
|
|
450
458
|
_apply_showif_plugins.forEach((p) => p());
|
package/public/saltcorn.js
CHANGED
package/routes/admin.js
CHANGED
|
@@ -312,6 +312,12 @@ router.get(
|
|
|
312
312
|
backupForm.values.backup_with_event_log = getState().getConfig(
|
|
313
313
|
"backup_with_event_log"
|
|
314
314
|
);
|
|
315
|
+
backupForm.values.backup_with_system_zip = getState().getConfig(
|
|
316
|
+
"backup_with_system_zip"
|
|
317
|
+
);
|
|
318
|
+
backupForm.values.backup_system_zip_level = getState().getConfig(
|
|
319
|
+
"backup_system_zip_level"
|
|
320
|
+
);
|
|
315
321
|
//
|
|
316
322
|
const aSnapshotForm = snapshotForm(req);
|
|
317
323
|
aSnapshotForm.values.snapshots_enabled =
|
|
@@ -838,6 +844,31 @@ const autoBackupForm = (req) => {
|
|
|
838
844
|
auto_backup_frequency: ["Daily", "Weekly"],
|
|
839
845
|
},
|
|
840
846
|
},
|
|
847
|
+
{
|
|
848
|
+
type: "Bool",
|
|
849
|
+
label: req.__("Use system zip"),
|
|
850
|
+
sublabel: req.__(
|
|
851
|
+
"Recommended. Executable <code>zip</code> must be installed"
|
|
852
|
+
),
|
|
853
|
+
name: "backup_with_system_zip",
|
|
854
|
+
showIf: {
|
|
855
|
+
auto_backup_frequency: ["Daily", "Weekly"],
|
|
856
|
+
},
|
|
857
|
+
},
|
|
858
|
+
{
|
|
859
|
+
type: "Integer",
|
|
860
|
+
label: req.__("Zip compression level"),
|
|
861
|
+
sublabel: req.__("1=Fast, larger file, 9=Slow, smaller files"),
|
|
862
|
+
name: "backup_system_zip_level",
|
|
863
|
+
attributes: {
|
|
864
|
+
min: 1,
|
|
865
|
+
max: 9,
|
|
866
|
+
},
|
|
867
|
+
showIf: {
|
|
868
|
+
auto_backup_frequency: ["Daily", "Weekly"],
|
|
869
|
+
backup_with_system_zip: true,
|
|
870
|
+
},
|
|
871
|
+
},
|
|
841
872
|
],
|
|
842
873
|
});
|
|
843
874
|
};
|
package/routes/files.js
CHANGED
|
@@ -20,7 +20,15 @@ const {
|
|
|
20
20
|
setTenant,
|
|
21
21
|
is_relative_url,
|
|
22
22
|
} = require("./utils.js");
|
|
23
|
-
const {
|
|
23
|
+
const {
|
|
24
|
+
h1,
|
|
25
|
+
div,
|
|
26
|
+
text,
|
|
27
|
+
script,
|
|
28
|
+
style,
|
|
29
|
+
link,
|
|
30
|
+
domReady,
|
|
31
|
+
} = require("@saltcorn/markup/tags");
|
|
24
32
|
const { editRoleForm, fileUploadForm } = require("../markup/forms.js");
|
|
25
33
|
const { strictParseInt } = require("@saltcorn/data/plugin-helper");
|
|
26
34
|
const {
|
|
@@ -43,20 +51,98 @@ const { extract } = require("@saltcorn/admin-models/models/backup");
|
|
|
43
51
|
const router = new Router();
|
|
44
52
|
module.exports = router;
|
|
45
53
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
54
|
+
const send_files_picker = async (folder, noSubdirs, inputId, req, res) => {
|
|
55
|
+
res.set("SaltcornModalWidth", "1200px");
|
|
56
|
+
res.sendWrap(req.__("Please select a file"), {
|
|
57
|
+
above: [
|
|
58
|
+
script({
|
|
59
|
+
src: `/static_assets/${db.connectObj.version_tag}/bundle.js`,
|
|
60
|
+
defer: true,
|
|
61
|
+
}),
|
|
62
|
+
script(
|
|
63
|
+
domReady(
|
|
64
|
+
`$("head").append('${link({
|
|
65
|
+
rel: "stylesheet",
|
|
66
|
+
href: `/static_assets/${db.connectObj.version_tag}/bundle.css`,
|
|
67
|
+
})}')`
|
|
68
|
+
)
|
|
69
|
+
),
|
|
70
|
+
div({
|
|
71
|
+
id: "saltcorn-file-manager",
|
|
72
|
+
full_manager: "false",
|
|
73
|
+
folder: folder,
|
|
74
|
+
input_id: inputId,
|
|
75
|
+
...(noSubdirs ? { no_subdirs: "true" } : {}),
|
|
76
|
+
}),
|
|
77
|
+
],
|
|
59
78
|
});
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
router.get(
|
|
82
|
+
"/picker",
|
|
83
|
+
error_catcher(async (req, res) => {
|
|
84
|
+
const { folder, input_id, no_subdirs } = req.query;
|
|
85
|
+
send_files_picker(folder, no_subdirs, input_id, req, res);
|
|
86
|
+
})
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
router.get(
|
|
90
|
+
"/visible_entries",
|
|
91
|
+
error_catcher(async (req, res) => {
|
|
92
|
+
const role = req.user?.role_id ? req.user.role_id : 100;
|
|
93
|
+
const userId = req.user?.id;
|
|
94
|
+
const { dir, no_subdirs } = req.query;
|
|
95
|
+
const noSubdirs = no_subdirs === "true";
|
|
96
|
+
const safeDir = File.normalise(dir || "/");
|
|
97
|
+
const absFolder = path.join(
|
|
98
|
+
db.connectObj.file_store,
|
|
99
|
+
db.getTenantSchema(),
|
|
100
|
+
safeDir
|
|
101
|
+
);
|
|
102
|
+
const dirOnDisk = await File.from_file_on_disk(
|
|
103
|
+
path.basename(absFolder),
|
|
104
|
+
path.dirname(absFolder)
|
|
105
|
+
);
|
|
106
|
+
if (dirOnDisk.min_role_read < role) {
|
|
107
|
+
getState().log(5, `Directory denied. path=${dir} role=${role}`);
|
|
108
|
+
res.json({ files: [], roles: [], directories: [] });
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const rows = (
|
|
112
|
+
await File.find({ folder: dir }, { orderBy: "filename" })
|
|
113
|
+
).filter((f) => {
|
|
114
|
+
if (noSubdirs && f.isDirectory) return false;
|
|
115
|
+
else return role <= f.min_role_read || (userId && userId === f.user_id);
|
|
116
|
+
});
|
|
117
|
+
const roles = await User.get_roles();
|
|
118
|
+
if (!no_subdirs && safeDir && safeDir !== "/" && safeDir !== ".") {
|
|
119
|
+
let dirname = path.dirname(safeDir);
|
|
120
|
+
if (dirname === ".") dirname = "/";
|
|
121
|
+
rows.unshift(
|
|
122
|
+
new File({
|
|
123
|
+
filename: "..",
|
|
124
|
+
location: dirname,
|
|
125
|
+
isDirectory: true,
|
|
126
|
+
mime_super: "",
|
|
127
|
+
mime_sub: "",
|
|
128
|
+
})
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
for (const file of rows) {
|
|
133
|
+
file.location = file.path_to_serve;
|
|
134
|
+
}
|
|
135
|
+
const directories = !noSubdirs
|
|
136
|
+
? (await File.allDirectories(true)).filter(
|
|
137
|
+
(dir) => role <= dir.min_role_read
|
|
138
|
+
)
|
|
139
|
+
: [];
|
|
140
|
+
for (const dir of directories) {
|
|
141
|
+
dir.location = dir.path_to_serve;
|
|
142
|
+
}
|
|
143
|
+
res.json({ files: rows, roles, directories });
|
|
144
|
+
})
|
|
145
|
+
);
|
|
60
146
|
|
|
61
147
|
/**
|
|
62
148
|
* @name get
|
|
@@ -116,7 +202,7 @@ router.get(
|
|
|
116
202
|
contents: {
|
|
117
203
|
type: "card",
|
|
118
204
|
contents: [
|
|
119
|
-
div({ id: "saltcorn-file-manager" }),
|
|
205
|
+
div({ full_manager: "true", id: "saltcorn-file-manager" }),
|
|
120
206
|
fileUploadForm(req, safeDir),
|
|
121
207
|
],
|
|
122
208
|
},
|
package/routes/notifications.js
CHANGED
|
@@ -14,6 +14,7 @@ const Form = require("@saltcorn/data/models/form");
|
|
|
14
14
|
const File = require("@saltcorn/data/models/file");
|
|
15
15
|
const User = require("@saltcorn/data/models/user");
|
|
16
16
|
const { renderForm, post_btn } = require("@saltcorn/markup");
|
|
17
|
+
const db = require("@saltcorn/data/db");
|
|
17
18
|
|
|
18
19
|
const router = new Router();
|
|
19
20
|
module.exports = router;
|
|
@@ -39,9 +40,18 @@ router.get(
|
|
|
39
40
|
orderDesc: true,
|
|
40
41
|
limit: 20,
|
|
41
42
|
});
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
const unreads = nots.filter((n) => !n.read);
|
|
44
|
+
if (unreads.length > 0)
|
|
45
|
+
await Notification.mark_as_read(
|
|
46
|
+
!db.isSQLite
|
|
47
|
+
? {
|
|
48
|
+
id: { in: unreads.map((n) => n.id) },
|
|
49
|
+
}
|
|
50
|
+
: {
|
|
51
|
+
or: unreads.map((n) => ({ id: n.id })),
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
|
|
45
55
|
const form = notificationSettingsForm();
|
|
46
56
|
const user = await User.findOne({ id: req.user?.id });
|
|
47
57
|
form.values = { notify_email: user?._attributes?.notify_email };
|
package/routes/viewedit.js
CHANGED
|
@@ -186,7 +186,11 @@ const viewForm = async (req, tableOptions, roles, pages, values) => {
|
|
|
186
186
|
sublabel: req.__("Display data from this table"),
|
|
187
187
|
options: tableOptions,
|
|
188
188
|
disabled: isEdit,
|
|
189
|
-
showIf:
|
|
189
|
+
showIf: isEdit
|
|
190
|
+
? hasTable.includes(values.viewtemplate)
|
|
191
|
+
? undefined
|
|
192
|
+
: { nosuchvar: true }
|
|
193
|
+
: { viewtemplate: hasTable },
|
|
190
194
|
}),
|
|
191
195
|
new Field({
|
|
192
196
|
name: "min_role",
|
|
@@ -242,7 +246,11 @@ const viewForm = async (req, tableOptions, roles, pages, values) => {
|
|
|
242
246
|
mapObjectValues(slugOptions, (lvs) => lvs.map((lv) => lv.label)),
|
|
243
247
|
],
|
|
244
248
|
},
|
|
245
|
-
showIf:
|
|
249
|
+
showIf: isEdit
|
|
250
|
+
? hasTable.includes(values.viewtemplate)
|
|
251
|
+
? undefined
|
|
252
|
+
: { nosuchvar: true }
|
|
253
|
+
: { viewtemplate: hasTable },
|
|
246
254
|
}),
|
|
247
255
|
new Field({
|
|
248
256
|
name: "no_menu",
|
package/tests/files.test.js
CHANGED
|
@@ -30,6 +30,14 @@ const createTestFile = async (folder, name, mimetype, content) => {
|
|
|
30
30
|
}
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
+
const checkFiles = (files, expecteds) =>
|
|
34
|
+
files.length >= expecteds.length &&
|
|
35
|
+
expecteds.every(({ filename, location }) =>
|
|
36
|
+
files.find(
|
|
37
|
+
(file) => file.filename === filename && file.location === location
|
|
38
|
+
)
|
|
39
|
+
);
|
|
40
|
+
|
|
33
41
|
beforeAll(async () => {
|
|
34
42
|
await resetToFixtures();
|
|
35
43
|
await File.ensure_file_store();
|
|
@@ -186,13 +194,7 @@ describe("files admin", () => {
|
|
|
186
194
|
it("search files by name", async () => {
|
|
187
195
|
const app = await getApp({ disableCsrf: true });
|
|
188
196
|
const loginCookie = await getAdminLoginCookie();
|
|
189
|
-
|
|
190
|
-
files.length >= expecteds.length &&
|
|
191
|
-
expecteds.every(({ filename, location }) =>
|
|
192
|
-
files.find(
|
|
193
|
-
(file) => file.filename === filename && file.location === location
|
|
194
|
-
)
|
|
195
|
-
);
|
|
197
|
+
|
|
196
198
|
const searchTestHelper = async (dir, search, expected) => {
|
|
197
199
|
await request(app)
|
|
198
200
|
.get("/files")
|
|
@@ -345,3 +347,81 @@ describe("files edit", () => {
|
|
|
345
347
|
expect(!!file).toBe(true);
|
|
346
348
|
});
|
|
347
349
|
});
|
|
350
|
+
|
|
351
|
+
describe("visible_entries test", () => {
|
|
352
|
+
const setRole = async (role, entry) => {
|
|
353
|
+
const app = await getApp({ disableCsrf: true });
|
|
354
|
+
const adminCookie = await getAdminLoginCookie();
|
|
355
|
+
await request(app)
|
|
356
|
+
.post(`/files/setrole/${entry}`)
|
|
357
|
+
.set("Cookie", adminCookie)
|
|
358
|
+
.send(`role=${role}`)
|
|
359
|
+
.expect(toRedirect("/files?dir=_sc_test_subfolder_one"));
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
it("shows allowed files", async () => {
|
|
363
|
+
await setRole(100, path.join("_sc_test_subfolder_one", "foo_image.png"));
|
|
364
|
+
|
|
365
|
+
const app = await getApp({ disableCsrf: true });
|
|
366
|
+
const staffCookie = await getStaffLoginCookie();
|
|
367
|
+
await request(app)
|
|
368
|
+
.get("/files/visible_entries?dir=_sc_test_subfolder_one")
|
|
369
|
+
.set("Cookie", staffCookie)
|
|
370
|
+
.expect(
|
|
371
|
+
respondJsonWith(200, (data) =>
|
|
372
|
+
checkFiles(data.files, [
|
|
373
|
+
{
|
|
374
|
+
filename: "foo_image.png",
|
|
375
|
+
location: path.join("_sc_test_subfolder_one", "foo_image.png"),
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
filename: "bar_image.png",
|
|
379
|
+
location: path.join("_sc_test_subfolder_one", "bar_image.png"),
|
|
380
|
+
},
|
|
381
|
+
])
|
|
382
|
+
)
|
|
383
|
+
);
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
it("shows no disallowed files", async () => {
|
|
387
|
+
await setRole(1, path.join("_sc_test_subfolder_one", "foo_image.png"));
|
|
388
|
+
const app = await getApp({ disableCsrf: true });
|
|
389
|
+
const staffCookie = await getStaffLoginCookie();
|
|
390
|
+
const resp = await request(app)
|
|
391
|
+
.get("/files/visible_entries?dir=_sc_test_subfolder_one")
|
|
392
|
+
.set("Cookie", staffCookie);
|
|
393
|
+
expect(resp.statusCode).toBe(200);
|
|
394
|
+
const files = resp.body.files;
|
|
395
|
+
expect(
|
|
396
|
+
files.find((file) => file.filename === "foo_image.png")
|
|
397
|
+
).toBeUndefined();
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
it("shows allowed directories", async () => {
|
|
401
|
+
const dir = path.join("_sc_test_subfolder_one", "subsubfolder");
|
|
402
|
+
await setRole(80, dir);
|
|
403
|
+
const app = await getApp({ disableCsrf: true });
|
|
404
|
+
const staffCookie = await getStaffLoginCookie();
|
|
405
|
+
const resp = await request(app)
|
|
406
|
+
.get(`/files/visible_entries?dir=${dir}`)
|
|
407
|
+
.set("Cookie", staffCookie);
|
|
408
|
+
expect(resp.statusCode).toBe(200);
|
|
409
|
+
expect(
|
|
410
|
+
resp.body.directories.find((file) => file.filename === "subsubfolder")
|
|
411
|
+
).toBeDefined();
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
it("shows no disallowed directories", async () => {
|
|
415
|
+
const dir = path.join("_sc_test_subfolder_one", "subsubfolder");
|
|
416
|
+
await setRole(1, dir);
|
|
417
|
+
const app = await getApp({ disableCsrf: true });
|
|
418
|
+
const staffCookie = await getStaffLoginCookie();
|
|
419
|
+
const resp = await request(app)
|
|
420
|
+
.get(`/files/visible_entries?dir=${dir}`)
|
|
421
|
+
.set("Cookie", staffCookie);
|
|
422
|
+
expect(resp.statusCode).toBe(200);
|
|
423
|
+
const body = resp.body;
|
|
424
|
+
expect(body.files.length).toBe(0);
|
|
425
|
+
expect(body.directories.length).toBe(0);
|
|
426
|
+
});
|
|
427
|
+
});
|