@saltcorn/server 0.7.4-beta.3 → 0.8.0-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/app.js +43 -22
- package/auth/admin.js +173 -74
- package/auth/routes.js +67 -28
- package/locales/en.json +54 -2
- package/locales/es.json +134 -134
- package/locales/ru.json +32 -5
- package/markup/admin.js +40 -38
- package/markup/forms.js +4 -3
- package/package.json +8 -7
- package/public/diagram_utils.js +530 -0
- package/public/gridedit.js +4 -1
- package/public/jquery-menu-editor.min.js +112 -112
- package/public/saltcorn-common.js +114 -26
- package/public/saltcorn.css +27 -10
- package/public/saltcorn.js +223 -76
- package/restart_watcher.js +1 -0
- package/routes/actions.js +20 -6
- package/routes/admin.js +243 -82
- package/routes/api.js +19 -2
- package/routes/common_lists.js +137 -134
- package/routes/diagram.js +362 -35
- package/routes/fields.js +4 -1
- package/routes/files.js +137 -101
- package/routes/homepage.js +2 -2
- package/routes/infoarch.js +2 -2
- package/routes/list.js +4 -4
- package/routes/page.js +16 -3
- package/routes/pageedit.js +22 -14
- package/routes/scapi.js +1 -1
- package/routes/search.js +1 -1
- package/routes/tables.js +4 -5
- package/routes/tag_entries.js +31 -10
- package/routes/tags.js +36 -32
- package/routes/tenant.js +98 -36
- package/routes/utils.js +72 -20
- package/routes/view.js +0 -1
- package/routes/viewedit.js +55 -22
- package/serve.js +5 -0
- package/tests/admin.test.js +2 -0
- package/tests/auth.test.js +20 -0
- package/tests/files.test.js +11 -20
- package/tests/tenant.test.js +4 -2
package/routes/admin.js
CHANGED
|
@@ -97,13 +97,6 @@ const { getConfigFile } = require("@saltcorn/data/db/connect");
|
|
|
97
97
|
const os = require("os");
|
|
98
98
|
const Page = require("@saltcorn/data/models/page");
|
|
99
99
|
|
|
100
|
-
/**
|
|
101
|
-
* @type {object}
|
|
102
|
-
* @const
|
|
103
|
-
* @namespace routes/adminRouter
|
|
104
|
-
* @category server
|
|
105
|
-
* @subcategory routes
|
|
106
|
-
*/
|
|
107
100
|
const router = new Router();
|
|
108
101
|
module.exports = router;
|
|
109
102
|
|
|
@@ -123,9 +116,6 @@ const site_id_form = (req) =>
|
|
|
123
116
|
"base_url",
|
|
124
117
|
"page_custom_css",
|
|
125
118
|
"page_custom_html",
|
|
126
|
-
"development_mode",
|
|
127
|
-
"log_sql",
|
|
128
|
-
"log_level",
|
|
129
119
|
"plugins_store_endpoint",
|
|
130
120
|
"packs_store_endpoint",
|
|
131
121
|
...(getConfigFile() ? ["multitenancy_enabled"] : []),
|
|
@@ -139,7 +129,7 @@ const site_id_form = (req) =>
|
|
|
139
129
|
* @returns {Promise<Form>} form
|
|
140
130
|
*/
|
|
141
131
|
const email_form = async (req) => {
|
|
142
|
-
|
|
132
|
+
return await config_fields_form({
|
|
143
133
|
req,
|
|
144
134
|
field_names: [
|
|
145
135
|
"smtp_host",
|
|
@@ -151,10 +141,9 @@ const email_form = async (req) => {
|
|
|
151
141
|
],
|
|
152
142
|
action: "/admin/email",
|
|
153
143
|
});
|
|
154
|
-
return form;
|
|
155
144
|
};
|
|
156
145
|
|
|
157
|
-
const app_files_table = (files, req) =>
|
|
146
|
+
const app_files_table = (files, buildDirName, req) =>
|
|
158
147
|
mkTable(
|
|
159
148
|
[
|
|
160
149
|
{
|
|
@@ -163,9 +152,21 @@ const app_files_table = (files, req) =>
|
|
|
163
152
|
},
|
|
164
153
|
{ label: req.__("Size (KiB)"), key: "size_kb", align: "right" },
|
|
165
154
|
{ label: req.__("Media type"), key: (r) => r.mimetype },
|
|
155
|
+
{
|
|
156
|
+
label: req.__("Open"),
|
|
157
|
+
key: (r) =>
|
|
158
|
+
link(
|
|
159
|
+
`/files/serve/mobile_app/${buildDirName}/${r.filename}`,
|
|
160
|
+
req.__("Open")
|
|
161
|
+
),
|
|
162
|
+
},
|
|
166
163
|
{
|
|
167
164
|
label: req.__("Download"),
|
|
168
|
-
key: (r) =>
|
|
165
|
+
key: (r) =>
|
|
166
|
+
link(
|
|
167
|
+
`/files/download/mobile_app/${buildDirName}/${r.filename}`,
|
|
168
|
+
req.__("Download")
|
|
169
|
+
),
|
|
169
170
|
},
|
|
170
171
|
],
|
|
171
172
|
files
|
|
@@ -476,10 +477,10 @@ router.get(
|
|
|
476
477
|
li(
|
|
477
478
|
a({ href: "/admin/clear-all" }, req.__("Clear this application")),
|
|
478
479
|
" ",
|
|
479
|
-
|
|
480
|
+
req.__("(tick all boxes)")
|
|
480
481
|
),
|
|
481
482
|
li(
|
|
482
|
-
|
|
483
|
+
req.__("When prompted to create the first user, click the link to restore a backup")
|
|
483
484
|
),
|
|
484
485
|
li(req.__("Select the downloaded backup file"))
|
|
485
486
|
)
|
|
@@ -734,6 +735,7 @@ router.post(
|
|
|
734
735
|
await auto_backup_now();
|
|
735
736
|
req.flash("success", req.__("Backup successful"));
|
|
736
737
|
} catch (e) {
|
|
738
|
+
getState().log(1, e);
|
|
737
739
|
req.flash("error", e.message);
|
|
738
740
|
}
|
|
739
741
|
res.json({ reload_page: true });
|
|
@@ -873,12 +875,40 @@ router.get(
|
|
|
873
875
|
),
|
|
874
876
|
tr(th(req.__("Node.js version")), td(process.version)),
|
|
875
877
|
tr(
|
|
876
|
-
th(req.__("Database")),
|
|
878
|
+
th(req.__("Database type")),
|
|
877
879
|
td(db.isSQLite ? "SQLite " : "PostgreSQL ", dbversion)
|
|
878
880
|
),
|
|
881
|
+
(isRoot?
|
|
882
|
+
tr(
|
|
883
|
+
th(req.__("Database host")),
|
|
884
|
+
td(db.connectObj.host)
|
|
885
|
+
)
|
|
886
|
+
: ""),
|
|
887
|
+
(isRoot?
|
|
888
|
+
tr(
|
|
889
|
+
th(req.__("Database port")),
|
|
890
|
+
td(db.connectObj.port)
|
|
891
|
+
)
|
|
892
|
+
: ""),
|
|
893
|
+
(isRoot?
|
|
894
|
+
tr(
|
|
895
|
+
th(req.__("Database name")),
|
|
896
|
+
td(db.connectObj.database)
|
|
897
|
+
)
|
|
898
|
+
: ""),
|
|
899
|
+
(isRoot?
|
|
900
|
+
tr(
|
|
901
|
+
th(req.__("Database user")),
|
|
902
|
+
td(db.connectObj.user)
|
|
903
|
+
)
|
|
904
|
+
: ""),
|
|
879
905
|
tr(
|
|
880
|
-
|
|
881
|
-
|
|
906
|
+
th(req.__("Database schema")),
|
|
907
|
+
td(db.getTenantSchema())
|
|
908
|
+
),
|
|
909
|
+
tr(
|
|
910
|
+
th(req.__("Process uptime")),
|
|
911
|
+
td(moment(get_process_init_time()).fromNow(true))
|
|
882
912
|
)
|
|
883
913
|
)
|
|
884
914
|
),
|
|
@@ -980,7 +1010,7 @@ router.post(
|
|
|
980
1010
|
res.attachment(fileName);
|
|
981
1011
|
const file = fs.createReadStream(fileName);
|
|
982
1012
|
file.on("end", function () {
|
|
983
|
-
fs.unlink(fileName, function () {
|
|
1013
|
+
fs.unlink(fileName, function () {});
|
|
984
1014
|
});
|
|
985
1015
|
file.pipe(res);
|
|
986
1016
|
})
|
|
@@ -1003,7 +1033,7 @@ router.post(
|
|
|
1003
1033
|
);
|
|
1004
1034
|
if (err) req.flash("error", err);
|
|
1005
1035
|
else req.flash("success", req.__("Successfully restored backup"));
|
|
1006
|
-
fs.unlink(newPath, function () {
|
|
1036
|
+
fs.unlink(newPath, function () {});
|
|
1007
1037
|
res.redirect(`/admin`);
|
|
1008
1038
|
})
|
|
1009
1039
|
);
|
|
@@ -1198,12 +1228,17 @@ router.get(
|
|
|
1198
1228
|
"/configuration-check",
|
|
1199
1229
|
isAdmin,
|
|
1200
1230
|
error_catcher(async (req, res) => {
|
|
1201
|
-
const { passes, errors, pass } = await runConfigurationCheck(req);
|
|
1231
|
+
const { passes, errors, pass, warnings } = await runConfigurationCheck(req);
|
|
1202
1232
|
const mkError = (err) =>
|
|
1203
1233
|
div(
|
|
1204
1234
|
{ class: "alert alert-danger", role: "alert" },
|
|
1205
1235
|
pre({ class: "mb-0" }, code(err))
|
|
1206
1236
|
);
|
|
1237
|
+
const mkWarning = (err) =>
|
|
1238
|
+
div(
|
|
1239
|
+
{ class: "alert alert-warning", role: "alert" },
|
|
1240
|
+
pre({ class: "mb-0" }, code(err))
|
|
1241
|
+
);
|
|
1207
1242
|
res.sendWrap(req.__(`Admin`), {
|
|
1208
1243
|
above: [
|
|
1209
1244
|
{
|
|
@@ -1227,7 +1262,8 @@ router.get(
|
|
|
1227
1262
|
req.__("No errors detected during configuration check")
|
|
1228
1263
|
)
|
|
1229
1264
|
)
|
|
1230
|
-
: errors.map(mkError)
|
|
1265
|
+
: errors.map(mkError),
|
|
1266
|
+
(warnings || []).map(mkWarning)
|
|
1231
1267
|
),
|
|
1232
1268
|
},
|
|
1233
1269
|
{
|
|
@@ -1283,7 +1319,9 @@ const buildDialogScript = () => {
|
|
|
1283
1319
|
}
|
|
1284
1320
|
</script>`;
|
|
1285
1321
|
};
|
|
1286
|
-
|
|
1322
|
+
/**
|
|
1323
|
+
* Build mobile app
|
|
1324
|
+
*/
|
|
1287
1325
|
router.get(
|
|
1288
1326
|
"/build-mobile-app",
|
|
1289
1327
|
isAdmin,
|
|
@@ -1476,8 +1514,9 @@ router.get(
|
|
|
1476
1514
|
),
|
|
1477
1515
|
button(
|
|
1478
1516
|
{
|
|
1479
|
-
|
|
1480
|
-
|
|
1517
|
+
id: "buildMobileAppBtnId",
|
|
1518
|
+
type: "button",
|
|
1519
|
+
onClick: `build_mobile_app(this);`,
|
|
1481
1520
|
class: "btn btn-warning",
|
|
1482
1521
|
},
|
|
1483
1522
|
i({ class: "fas fa-hammer pe-2" }),
|
|
@@ -1493,6 +1532,57 @@ router.get(
|
|
|
1493
1532
|
})
|
|
1494
1533
|
);
|
|
1495
1534
|
|
|
1535
|
+
const checkFiles = async (outDir, fileNames) => {
|
|
1536
|
+
const rootFolder = await File.rootFolder();
|
|
1537
|
+
const mobile_app_dir = path.join(rootFolder.location, "mobile_app", outDir);
|
|
1538
|
+
const entries = fs.readdirSync(mobile_app_dir);
|
|
1539
|
+
return fileNames.some((fileName) => entries.indexOf(fileName) >= 0);
|
|
1540
|
+
};
|
|
1541
|
+
|
|
1542
|
+
// check if a build has finished (poll service)
|
|
1543
|
+
router.get(
|
|
1544
|
+
"/build-mobile-app/finished",
|
|
1545
|
+
isAdmin,
|
|
1546
|
+
error_catcher(async (req, res) => {
|
|
1547
|
+
const { build_dir } = req.query;
|
|
1548
|
+
res.json({
|
|
1549
|
+
finished: await checkFiles(build_dir, ["logs.txt", "error_logs.txt"]),
|
|
1550
|
+
});
|
|
1551
|
+
})
|
|
1552
|
+
);
|
|
1553
|
+
|
|
1554
|
+
router.get(
|
|
1555
|
+
"/build-mobile-app/result",
|
|
1556
|
+
isAdmin,
|
|
1557
|
+
error_catcher(async (req, res) => {
|
|
1558
|
+
const { build_dir_name } = req.query;
|
|
1559
|
+
const rootFolder = await File.rootFolder();
|
|
1560
|
+
const buildDir = path.join(
|
|
1561
|
+
rootFolder.location,
|
|
1562
|
+
"mobile_app",
|
|
1563
|
+
build_dir_name
|
|
1564
|
+
);
|
|
1565
|
+
const files = await Promise.all(
|
|
1566
|
+
fs
|
|
1567
|
+
.readdirSync(buildDir)
|
|
1568
|
+
.map(async (outFile) => await File.from_file_on_disk(outFile, buildDir))
|
|
1569
|
+
);
|
|
1570
|
+
const resultMsg = files.find((file) => file.filename === "logs.txt")
|
|
1571
|
+
? req.__("The build was successfully")
|
|
1572
|
+
: req.__("Unable to build the app");
|
|
1573
|
+
res.sendWrap(req.__(`Admin`), {
|
|
1574
|
+
above: [
|
|
1575
|
+
{
|
|
1576
|
+
type: "card",
|
|
1577
|
+
title: req.__("Build Result"),
|
|
1578
|
+
contents: div(resultMsg),
|
|
1579
|
+
},
|
|
1580
|
+
files.length > 0 ? app_files_table(files, build_dir_name, req) : "",
|
|
1581
|
+
],
|
|
1582
|
+
});
|
|
1583
|
+
})
|
|
1584
|
+
);
|
|
1585
|
+
|
|
1496
1586
|
router.post(
|
|
1497
1587
|
"/build-mobile-app",
|
|
1498
1588
|
isAdmin,
|
|
@@ -1507,24 +1597,27 @@ router.post(
|
|
|
1507
1597
|
serverURL,
|
|
1508
1598
|
} = req.body;
|
|
1509
1599
|
if (!androidPlatform && !iOSPlatform) {
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
);
|
|
1514
|
-
return res.redirect("/admin/build-mobile-app");
|
|
1600
|
+
return res.json({
|
|
1601
|
+
error: req.__("Please select at least one platform (android or iOS)."),
|
|
1602
|
+
});
|
|
1515
1603
|
}
|
|
1516
1604
|
if (!androidPlatform && useDocker) {
|
|
1517
|
-
|
|
1518
|
-
|
|
1605
|
+
return res.json({
|
|
1606
|
+
error: req.__("Only the android build supports docker."),
|
|
1607
|
+
});
|
|
1519
1608
|
}
|
|
1520
1609
|
if (!serverURL || serverURL.length == 0) {
|
|
1521
1610
|
serverURL = getState().getConfig("base_url") || "";
|
|
1522
1611
|
}
|
|
1523
1612
|
if (!serverURL.startsWith("http")) {
|
|
1524
|
-
|
|
1525
|
-
|
|
1613
|
+
return res.json({
|
|
1614
|
+
error: req.__("Please enter a valid server URL."),
|
|
1615
|
+
});
|
|
1526
1616
|
}
|
|
1527
|
-
const
|
|
1617
|
+
const outDirName = `build_${new Date().valueOf()}`;
|
|
1618
|
+
const rootFolder = await File.rootFolder();
|
|
1619
|
+
const buildDir = path.join(rootFolder.location, "mobile_app", outDirName);
|
|
1620
|
+
await File.new_folder(outDirName, "/mobile_app");
|
|
1528
1621
|
const spawnParams = [
|
|
1529
1622
|
"build-app",
|
|
1530
1623
|
"-e",
|
|
@@ -1532,7 +1625,7 @@ router.post(
|
|
|
1532
1625
|
"-t",
|
|
1533
1626
|
entryPointType,
|
|
1534
1627
|
"-c",
|
|
1535
|
-
|
|
1628
|
+
buildDir,
|
|
1536
1629
|
"-b",
|
|
1537
1630
|
`${os.userInfo().homedir}/mobile_app_build`,
|
|
1538
1631
|
];
|
|
@@ -1547,6 +1640,15 @@ router.post(
|
|
|
1547
1640
|
}
|
|
1548
1641
|
if (appFile) spawnParams.push("-a", appFile);
|
|
1549
1642
|
if (serverURL) spawnParams.push("-s", serverURL);
|
|
1643
|
+
if (
|
|
1644
|
+
db.is_it_multi_tenant() &&
|
|
1645
|
+
db.getTenantSchema() !== db.connectObj.default_schema
|
|
1646
|
+
) {
|
|
1647
|
+
spawnParams.push("--tenantAppName", db.getTenantSchema());
|
|
1648
|
+
}
|
|
1649
|
+
// end http call, return the out directory name
|
|
1650
|
+
// the gui polls for results
|
|
1651
|
+
res.json({ build_dir_name: outDirName });
|
|
1550
1652
|
const child = spawn("saltcorn", spawnParams, {
|
|
1551
1653
|
stdio: ["ignore", "pipe", "pipe"],
|
|
1552
1654
|
cwd: ".",
|
|
@@ -1561,60 +1663,37 @@ router.post(
|
|
|
1561
1663
|
childOutputs.push(data.toString());
|
|
1562
1664
|
});
|
|
1563
1665
|
child.on("exit", async function (exitCode, signal) {
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
)
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
{
|
|
1576
|
-
type: "card",
|
|
1577
|
-
title: req.__("Build Result"),
|
|
1578
|
-
contents: div(req.__("The build was successfully")),
|
|
1579
|
-
},
|
|
1580
|
-
files.length > 0 ? app_files_table(files, req) : "",
|
|
1581
|
-
],
|
|
1582
|
-
});
|
|
1583
|
-
} else
|
|
1584
|
-
res.sendWrap(req.__(`Admin`), {
|
|
1585
|
-
above: [
|
|
1586
|
-
{
|
|
1587
|
-
type: "card",
|
|
1588
|
-
title: req.__("Build Result"),
|
|
1589
|
-
contents: div(
|
|
1590
|
-
req.__("Unable to build the app:"),
|
|
1591
|
-
pre(code(childOutputs.join("<br/>")))
|
|
1592
|
-
),
|
|
1593
|
-
},
|
|
1594
|
-
],
|
|
1595
|
-
});
|
|
1666
|
+
const logFile = exitCode === 0 ? "logs.txt" : "error_logs.txt";
|
|
1667
|
+
fs.writeFile(
|
|
1668
|
+
path.join(buildDir, logFile),
|
|
1669
|
+
childOutputs.join("\n"),
|
|
1670
|
+
(error) => {
|
|
1671
|
+
if (error) {
|
|
1672
|
+
console.log(`unable to write '${logFile}' to '${buildDir}'`);
|
|
1673
|
+
console.log(error);
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
);
|
|
1596
1677
|
});
|
|
1597
1678
|
child.on("error", function (msg) {
|
|
1598
1679
|
const message = msg.message ? msg.message : msg.code;
|
|
1599
1680
|
const stack = msg.stack ? msg.stack : "";
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
},
|
|
1611
|
-
],
|
|
1612
|
-
});
|
|
1681
|
+
fs.writeFile(
|
|
1682
|
+
path.join(buildDir, "error_logs.txt"),
|
|
1683
|
+
[message, stack].join("\n"),
|
|
1684
|
+
(error) => {
|
|
1685
|
+
if (error) {
|
|
1686
|
+
console.log(`unable to write '${logFile}' to '${buildDir}'`);
|
|
1687
|
+
console.log(error);
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
);
|
|
1613
1691
|
});
|
|
1614
1692
|
})
|
|
1615
1693
|
);
|
|
1616
1694
|
|
|
1617
1695
|
/**
|
|
1696
|
+
* Clear all
|
|
1618
1697
|
* @name post/clear-all
|
|
1619
1698
|
* @function
|
|
1620
1699
|
* @memberof module:routes/admin~routes/adminRouter
|
|
@@ -1733,3 +1812,85 @@ router.post(
|
|
|
1733
1812
|
}
|
|
1734
1813
|
})
|
|
1735
1814
|
);
|
|
1815
|
+
|
|
1816
|
+
/**
|
|
1817
|
+
* Developer settings form
|
|
1818
|
+
* @param {object} req request
|
|
1819
|
+
* @returns {Promise<Form>} form
|
|
1820
|
+
*/
|
|
1821
|
+
const dev_form = async (req) => {
|
|
1822
|
+
return await config_fields_form({
|
|
1823
|
+
req,
|
|
1824
|
+
field_names: [
|
|
1825
|
+
"development_mode",
|
|
1826
|
+
"log_sql",
|
|
1827
|
+
"log_level",
|
|
1828
|
+
],
|
|
1829
|
+
action: "/admin/dev",
|
|
1830
|
+
});
|
|
1831
|
+
};
|
|
1832
|
+
/**
|
|
1833
|
+
* Developer Mode page
|
|
1834
|
+
* @name get/dev
|
|
1835
|
+
* @function
|
|
1836
|
+
* @memberof module:routes/admin~routes/adminRouter
|
|
1837
|
+
*/
|
|
1838
|
+
router.get(
|
|
1839
|
+
"/dev",
|
|
1840
|
+
isAdmin,
|
|
1841
|
+
error_catcher(async (req, res) => {
|
|
1842
|
+
const form = await dev_form(req);
|
|
1843
|
+
send_admin_page({
|
|
1844
|
+
res,
|
|
1845
|
+
req,
|
|
1846
|
+
active_sub: "Development",
|
|
1847
|
+
contents: {
|
|
1848
|
+
type: "card",
|
|
1849
|
+
title: req.__("Development settings"),
|
|
1850
|
+
contents: [
|
|
1851
|
+
renderForm(form, req.csrfToken())/*,
|
|
1852
|
+
a(
|
|
1853
|
+
{
|
|
1854
|
+
id: "testemail",
|
|
1855
|
+
href: "/admin/send-test-email",
|
|
1856
|
+
class: "btn btn-primary",
|
|
1857
|
+
},
|
|
1858
|
+
req.__("Send test email")
|
|
1859
|
+
),*/
|
|
1860
|
+
],
|
|
1861
|
+
},
|
|
1862
|
+
});
|
|
1863
|
+
})
|
|
1864
|
+
);
|
|
1865
|
+
|
|
1866
|
+
/**
|
|
1867
|
+
* Development mode
|
|
1868
|
+
* @name post/email
|
|
1869
|
+
* @function
|
|
1870
|
+
* @memberof module:routes/admin~routes/adminRouter
|
|
1871
|
+
*/
|
|
1872
|
+
router.post(
|
|
1873
|
+
"/dev",
|
|
1874
|
+
isAdmin,
|
|
1875
|
+
error_catcher(async (req, res) => {
|
|
1876
|
+
const form = await dev_form(req);
|
|
1877
|
+
form.validate(req.body);
|
|
1878
|
+
if (form.hasErrors) {
|
|
1879
|
+
send_admin_page({
|
|
1880
|
+
res,
|
|
1881
|
+
req,
|
|
1882
|
+
active_sub: "Development",
|
|
1883
|
+
contents: {
|
|
1884
|
+
type: "card",
|
|
1885
|
+
title: req.__("Development settings"),
|
|
1886
|
+
contents: [renderForm(form, req.csrfToken())],
|
|
1887
|
+
},
|
|
1888
|
+
});
|
|
1889
|
+
} else {
|
|
1890
|
+
await save_config_from_form(form);
|
|
1891
|
+
req.flash("success", req.__("Development mode settings updated"));
|
|
1892
|
+
if (!req.xhr) res.redirect("/admin/dev");
|
|
1893
|
+
else res.json({ success: "ok" });
|
|
1894
|
+
}
|
|
1895
|
+
})
|
|
1896
|
+
);
|
package/routes/api.js
CHANGED
|
@@ -124,8 +124,17 @@ router.post(
|
|
|
124
124
|
error_catcher(async (req, res, next) => {
|
|
125
125
|
let { viewName, queryName } = req.params;
|
|
126
126
|
const view = await View.findOne({ name: viewName });
|
|
127
|
+
const db = require("@saltcorn/data/db");
|
|
127
128
|
if (!view) {
|
|
128
|
-
res.status(404).json({
|
|
129
|
+
res.status(404).json({
|
|
130
|
+
error: req.__("View %s not found", viewName),
|
|
131
|
+
view: viewName,
|
|
132
|
+
queryName: queryName,
|
|
133
|
+
smr: req.smr,
|
|
134
|
+
smrHeader: req.headers["x-saltcorn-client"],
|
|
135
|
+
schema: db.getTenantSchema(),
|
|
136
|
+
userTenant: req.user?.tenant,
|
|
137
|
+
});
|
|
129
138
|
return;
|
|
130
139
|
}
|
|
131
140
|
await passport.authenticate(
|
|
@@ -143,7 +152,15 @@ router.post(
|
|
|
143
152
|
const resp = await queries[queryName](...args, true);
|
|
144
153
|
res.json({ success: resp, alerts: getFlashes(req) });
|
|
145
154
|
} else {
|
|
146
|
-
res.status(404).json({
|
|
155
|
+
res.status(404).json({
|
|
156
|
+
error: req.__("Query %s not found", queryName),
|
|
157
|
+
view: viewName,
|
|
158
|
+
queryName: queryName,
|
|
159
|
+
smr: req.smr,
|
|
160
|
+
smrHeader: req.headers["x-saltcorn-client"],
|
|
161
|
+
schema: db.getTenantSchema(),
|
|
162
|
+
userTenant: req.user?.tenant,
|
|
163
|
+
});
|
|
147
164
|
}
|
|
148
165
|
} else {
|
|
149
166
|
res.status(401).json({ error: req.__("Not authorized") });
|