@saltcorn/server 0.9.5-beta.9 → 0.9.6-beta.0
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/auth/routes.js +54 -7
- package/help/Android App Signing.tmd +22 -0
- package/help/Provisioning Profile.tmd +60 -0
- package/help/xcodebuild.tmd +1 -0
- package/load_plugins.js +6 -0
- package/locales/en.json +27 -2
- package/locales/ru.json +1134 -1101
- package/package.json +9 -9
- package/public/saltcorn-common.js +174 -21
- package/public/saltcorn.css +4 -0
- package/public/saltcorn.js +81 -61
- package/restart_watcher.js +2 -0
- package/routes/actions.js +17 -1
- package/routes/admin.js +657 -77
- package/routes/api.js +4 -1
- package/routes/fields.js +107 -9
- package/routes/menu.js +12 -3
- package/routes/page.js +8 -2
- package/routes/pageedit.js +2 -1
- package/routes/plugins.js +266 -30
- package/routes/search.js +28 -2
- package/routes/tag_entries.js +3 -3
- package/routes/tenant.js +1 -0
- package/routes/utils.js +18 -2
- package/routes/view.js +15 -3
- package/s3storage.js +1 -0
- package/systemd.js +1 -1
- package/tests/page.test.js +11 -1
package/routes/search.js
CHANGED
|
@@ -52,6 +52,12 @@ const searchConfigForm = (tables, views, req) => {
|
|
|
52
52
|
attributes: { options: ok_views.map((v) => v.name).join() },
|
|
53
53
|
});
|
|
54
54
|
}
|
|
55
|
+
fields.push({
|
|
56
|
+
name: "search_table_description",
|
|
57
|
+
label: req.__("Description header"),
|
|
58
|
+
sublabel: req.__("Use table description instead of name as header"),
|
|
59
|
+
type: "Bool",
|
|
60
|
+
});
|
|
55
61
|
const blurb1 = req.__(
|
|
56
62
|
`Choose views for <a href="/search">search results</a> for each table.<br/>Set to blank to omit table from global search.`
|
|
57
63
|
);
|
|
@@ -84,7 +90,11 @@ router.get(
|
|
|
84
90
|
const views = await View.find({}, { orderBy: "name" });
|
|
85
91
|
const tables = await Table.find();
|
|
86
92
|
const form = searchConfigForm(tables, views, req);
|
|
87
|
-
form.values = getState().getConfig("globalSearch");
|
|
93
|
+
form.values = getState().getConfig("globalSearch", {});
|
|
94
|
+
form.values.search_table_description = getState().getConfig(
|
|
95
|
+
"search_table_description",
|
|
96
|
+
false
|
|
97
|
+
);
|
|
88
98
|
send_infoarch_page({
|
|
89
99
|
res,
|
|
90
100
|
req,
|
|
@@ -116,6 +126,13 @@ router.post(
|
|
|
116
126
|
const result = form.validate(req.body);
|
|
117
127
|
|
|
118
128
|
if (result.success) {
|
|
129
|
+
const search_table_description =
|
|
130
|
+
!!result.success.search_table_description;
|
|
131
|
+
await getState().setConfig(
|
|
132
|
+
"search_table_description",
|
|
133
|
+
search_table_description
|
|
134
|
+
);
|
|
135
|
+
delete result.success.search_table_description;
|
|
119
136
|
await getState().setConfig("globalSearch", result.success);
|
|
120
137
|
if (!req.xhr) res.redirect("/search/config");
|
|
121
138
|
else res.json({ success: "ok" });
|
|
@@ -175,6 +192,10 @@ const runSearch = async ({ q, _page, table }, req, res) => {
|
|
|
175
192
|
res.redirect("/");
|
|
176
193
|
return;
|
|
177
194
|
}
|
|
195
|
+
const search_table_description = getState().getConfig(
|
|
196
|
+
"search_table_description",
|
|
197
|
+
false
|
|
198
|
+
);
|
|
178
199
|
const current_page = parseInt(_page) || 1;
|
|
179
200
|
const offset = (current_page - 1) * page_size;
|
|
180
201
|
let resp = [];
|
|
@@ -184,6 +205,11 @@ const runSearch = async ({ q, _page, table }, req, res) => {
|
|
|
184
205
|
if (!viewName || viewName === "") continue;
|
|
185
206
|
tablesConfigured += 1;
|
|
186
207
|
if (table && tableName !== table) continue;
|
|
208
|
+
let sectionHeader = tableName;
|
|
209
|
+
if (search_table_description) {
|
|
210
|
+
sectionHeader =
|
|
211
|
+
Table.findOne({ name: tableName })?.description || tableName;
|
|
212
|
+
}
|
|
187
213
|
const view = await View.findOne({ name: viewName });
|
|
188
214
|
if (!view)
|
|
189
215
|
throw new InvalidConfiguration(
|
|
@@ -209,7 +235,7 @@ const runSearch = async ({ q, _page, table }, req, res) => {
|
|
|
209
235
|
tablesWithResults.push(tableName);
|
|
210
236
|
resp.push({
|
|
211
237
|
type: "card",
|
|
212
|
-
title: span({ id: tableName },
|
|
238
|
+
title: span({ id: tableName }, sectionHeader),
|
|
213
239
|
contents: vresps.map((vr) => vr.html).join("<hr>") + paginate,
|
|
214
240
|
});
|
|
215
241
|
}
|
package/routes/tag_entries.js
CHANGED
|
@@ -87,9 +87,9 @@ const formOptions = async (type, tag_id) => {
|
|
|
87
87
|
case "triggers": {
|
|
88
88
|
const ids = await tag.getTriggerIds();
|
|
89
89
|
return {
|
|
90
|
-
triggers:
|
|
91
|
-
|
|
92
|
-
),
|
|
90
|
+
triggers: (
|
|
91
|
+
await Trigger.findDB({}, { orderBy: "name", nocase: true })
|
|
92
|
+
).filter((value) => ids.indexOf(value.id) === -1),
|
|
93
93
|
};
|
|
94
94
|
}
|
|
95
95
|
}
|
package/routes/tenant.js
CHANGED
package/routes/utils.js
CHANGED
|
@@ -203,7 +203,15 @@ const setTenant = (req, res, next) => {
|
|
|
203
203
|
} else {
|
|
204
204
|
db.runWithTenant(other_domain, () => {
|
|
205
205
|
setLanguage(req, res, state);
|
|
206
|
-
state.
|
|
206
|
+
if (state.logLevel >= 5)
|
|
207
|
+
state.log(
|
|
208
|
+
5,
|
|
209
|
+
`${req.method} ${req.originalUrl}${
|
|
210
|
+
state.getConfig("log_ip_address", false)
|
|
211
|
+
? ` IP=${req.ip}`
|
|
212
|
+
: ""
|
|
213
|
+
}`
|
|
214
|
+
);
|
|
207
215
|
next();
|
|
208
216
|
});
|
|
209
217
|
}
|
|
@@ -216,7 +224,15 @@ const setTenant = (req, res, next) => {
|
|
|
216
224
|
} else {
|
|
217
225
|
db.runWithTenant(ten, () => {
|
|
218
226
|
setLanguage(req, res, state);
|
|
219
|
-
state.
|
|
227
|
+
if (state.logLevel >= 5)
|
|
228
|
+
state.log(
|
|
229
|
+
5,
|
|
230
|
+
`${req.method} ${req.originalUrl}${
|
|
231
|
+
state.getConfig("log_ip_address", false)
|
|
232
|
+
? ` IP=${req.ip}`
|
|
233
|
+
: ""
|
|
234
|
+
}`
|
|
235
|
+
);
|
|
220
236
|
next();
|
|
221
237
|
});
|
|
222
238
|
}
|
package/routes/view.js
CHANGED
|
@@ -45,7 +45,12 @@ router.get(
|
|
|
45
45
|
const view = await View.findOne({ name: viewname });
|
|
46
46
|
const role = req.user && req.user.id ? req.user.role_id : 100;
|
|
47
47
|
const state = getState();
|
|
48
|
-
state.log(
|
|
48
|
+
state.log(
|
|
49
|
+
3,
|
|
50
|
+
`Route /view/${viewname} user=${req.user?.id}${
|
|
51
|
+
state.getConfig("log_ip_address", false) ? ` IP=${req.ip}` : ""
|
|
52
|
+
}`
|
|
53
|
+
);
|
|
49
54
|
if (!view) {
|
|
50
55
|
req.flash("danger", req.__(`No such view: %s`, text(viewname)));
|
|
51
56
|
state.log(2, `View ${viewname} not found`);
|
|
@@ -207,7 +212,9 @@ router.post(
|
|
|
207
212
|
const state = getState();
|
|
208
213
|
state.log(
|
|
209
214
|
3,
|
|
210
|
-
`Route /view/${viewname} viewroute ${route} user=${req.user?.id}
|
|
215
|
+
`Route /view/${viewname} viewroute ${route} user=${req.user?.id}${
|
|
216
|
+
state.getConfig("log_ip_address", false) ? ` IP=${req.ip}` : ""
|
|
217
|
+
}`
|
|
211
218
|
);
|
|
212
219
|
|
|
213
220
|
const view = await View.findOne({ name: viewname });
|
|
@@ -240,7 +247,12 @@ router.post(
|
|
|
240
247
|
const role = req.user && req.user.id ? req.user.role_id : 100;
|
|
241
248
|
const query = { ...req.query };
|
|
242
249
|
const state = getState();
|
|
243
|
-
state.log(
|
|
250
|
+
state.log(
|
|
251
|
+
3,
|
|
252
|
+
`Route /view/${viewname} POST user=${req.user?.id}${
|
|
253
|
+
state.getConfig("log_ip_address", false) ? ` IP=${req.ip}` : ""
|
|
254
|
+
}`
|
|
255
|
+
);
|
|
244
256
|
const view = await View.findOne({ name: viewname });
|
|
245
257
|
if (!view) {
|
|
246
258
|
req.flash("danger", req.__(`No such view: %s`, text(viewname)));
|
package/s3storage.js
CHANGED
package/systemd.js
CHANGED
package/tests/page.test.js
CHANGED
|
@@ -30,7 +30,17 @@ const prepHtmlFiles = async () => {
|
|
|
30
30
|
const html = `<html><head><title>Landing page</title></head><body><h1>${content}</h1></body></html>`;
|
|
31
31
|
if (!existsSync(scFolder)) await File.new_folder(folder);
|
|
32
32
|
if (!existsSync(join(scFolder, name))) {
|
|
33
|
-
|
|
33
|
+
const file = await File.from_contents(
|
|
34
|
+
name,
|
|
35
|
+
"text/html",
|
|
36
|
+
html,
|
|
37
|
+
1,
|
|
38
|
+
1,
|
|
39
|
+
folder
|
|
40
|
+
);
|
|
41
|
+
file.location = File.absPathToServePath(file.location);
|
|
42
|
+
|
|
43
|
+
return file;
|
|
34
44
|
} else {
|
|
35
45
|
const file = await File.from_file_on_disk(name, scFolder);
|
|
36
46
|
fs.writeFileSync(file.location, html);
|