@saltcorn/server 0.7.4-beta.1 → 0.7.4-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/auth/routes.js +64 -86
- package/locales/en.json +36 -1
- package/locales/ru.json +60 -7
- package/markup/admin.js +17 -4
- package/markup/expression_blurb.js +1 -1
- package/package.json +7 -7
- package/public/blockly.js +11 -5
- package/public/gridedit.js +7 -2
- package/public/saltcorn-common.js +27 -29
- package/public/saltcorn.css +24 -1
- package/public/saltcorn.js +56 -19
- package/routes/actions.js +2 -39
- package/routes/admin.js +16 -17
- package/routes/api.js +7 -6
- package/routes/common_lists.js +419 -0
- package/routes/diagram.js +59 -0
- package/routes/fields.js +42 -12
- package/routes/index.js +6 -0
- package/routes/pageedit.js +14 -108
- package/routes/plugins.js +15 -15
- package/routes/tables.js +10 -41
- package/routes/tag_entries.js +173 -0
- package/routes/tags.js +266 -0
- package/routes/viewedit.js +19 -136
- package/tests/page.test.js +9 -0
- package/tests/viewedit.test.js +16 -0
package/routes/pageedit.js
CHANGED
|
@@ -19,6 +19,7 @@ const Trigger = require("@saltcorn/data/models/trigger");
|
|
|
19
19
|
const { getViews, traverseSync } = require("@saltcorn/data/models/layout");
|
|
20
20
|
const { add_to_menu } = require("@saltcorn/admin-models/models/pack");
|
|
21
21
|
const db = require("@saltcorn/data/db");
|
|
22
|
+
const { getPageList } = require("./common_lists");
|
|
22
23
|
|
|
23
24
|
const { isAdmin, error_catcher } = require("./utils.js");
|
|
24
25
|
const {
|
|
@@ -32,7 +33,6 @@ const {
|
|
|
32
33
|
settingsDropdown,
|
|
33
34
|
} = require("@saltcorn/markup");
|
|
34
35
|
const { getActionConfigFields } = require("@saltcorn/data/plugin-helper");
|
|
35
|
-
const { editRoleForm, wizardCardTitle } = require("../markup/forms.js");
|
|
36
36
|
const Library = require("@saltcorn/data/models/library");
|
|
37
37
|
|
|
38
38
|
/**
|
|
@@ -45,68 +45,6 @@ const Library = require("@saltcorn/data/models/library");
|
|
|
45
45
|
const router = new Router();
|
|
46
46
|
module.exports = router;
|
|
47
47
|
|
|
48
|
-
/**
|
|
49
|
-
* @param {object} page
|
|
50
|
-
* @param {*} roles
|
|
51
|
-
* @param {object} req
|
|
52
|
-
* @returns {Form}
|
|
53
|
-
*/
|
|
54
|
-
const editPageRoleForm = (page, roles, req) =>
|
|
55
|
-
editRoleForm({
|
|
56
|
-
url: `/pageedit/setrole/${page.id}`,
|
|
57
|
-
current_role: page.min_role,
|
|
58
|
-
roles,
|
|
59
|
-
req,
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* @param {object} page
|
|
64
|
-
* @param {object} req
|
|
65
|
-
* @returns {string}
|
|
66
|
-
*/
|
|
67
|
-
const page_dropdown = (page, req) =>
|
|
68
|
-
settingsDropdown(`dropdownMenuButton${page.id}`, [
|
|
69
|
-
a(
|
|
70
|
-
{
|
|
71
|
-
class: "dropdown-item",
|
|
72
|
-
href: `/page/${encodeURIComponent(page.name)}`,
|
|
73
|
-
},
|
|
74
|
-
'<i class="fas fa-running"></i> ' + req.__("Run")
|
|
75
|
-
),
|
|
76
|
-
a(
|
|
77
|
-
{
|
|
78
|
-
class: "dropdown-item",
|
|
79
|
-
href: `/pageedit/edit-properties/${encodeURIComponent(page.name)}`,
|
|
80
|
-
},
|
|
81
|
-
'<i class="fas fa-edit"></i> ' + req.__("Edit properties")
|
|
82
|
-
),
|
|
83
|
-
post_dropdown_item(
|
|
84
|
-
`/pageedit/add-to-menu/${page.id}`,
|
|
85
|
-
'<i class="fas fa-bars"></i> ' + req.__("Add to menu"),
|
|
86
|
-
req
|
|
87
|
-
),
|
|
88
|
-
post_dropdown_item(
|
|
89
|
-
`/pageedit/clone/${page.id}`,
|
|
90
|
-
'<i class="far fa-copy"></i> ' + req.__("Duplicate"),
|
|
91
|
-
req
|
|
92
|
-
),
|
|
93
|
-
a(
|
|
94
|
-
{
|
|
95
|
-
class: "dropdown-item",
|
|
96
|
-
href: `javascript:ajax_modal('/admin/snapshot-restore/page/${page.name}')`,
|
|
97
|
-
},
|
|
98
|
-
'<i class="fas fa-undo-alt"></i> ' + req.__("Restore")
|
|
99
|
-
),
|
|
100
|
-
div({ class: "dropdown-divider" }),
|
|
101
|
-
post_dropdown_item(
|
|
102
|
-
`/pageedit/delete/${page.id}`,
|
|
103
|
-
'<i class="far fa-trash-alt"></i> ' + req.__("Delete"),
|
|
104
|
-
req,
|
|
105
|
-
true,
|
|
106
|
-
page.name
|
|
107
|
-
),
|
|
108
|
-
]);
|
|
109
|
-
|
|
110
48
|
/**
|
|
111
49
|
*
|
|
112
50
|
* @param {object} req
|
|
@@ -188,7 +126,7 @@ const pageBuilderData = async (req, context) => {
|
|
|
188
126
|
for (const view of views) {
|
|
189
127
|
fixed_state_fields[view.name] = [];
|
|
190
128
|
const table = Table.findOne(view.table_id || view.exttable_name);
|
|
191
|
-
|
|
129
|
+
|
|
192
130
|
const fs = await view.get_state_fields();
|
|
193
131
|
for (const frec of fs) {
|
|
194
132
|
const f = new Field(frec);
|
|
@@ -236,46 +174,6 @@ const pageBuilderData = async (req, context) => {
|
|
|
236
174
|
};
|
|
237
175
|
};
|
|
238
176
|
|
|
239
|
-
/**
|
|
240
|
-
* @param {*} rows
|
|
241
|
-
* @param {*} roles
|
|
242
|
-
* @param {object} req
|
|
243
|
-
* @returns {div}
|
|
244
|
-
*/
|
|
245
|
-
const getPageList = (rows, roles, req) => {
|
|
246
|
-
return div(
|
|
247
|
-
mkTable(
|
|
248
|
-
[
|
|
249
|
-
{
|
|
250
|
-
label: req.__("Name"),
|
|
251
|
-
key: (r) => link(`/page/${r.name}`, r.name),
|
|
252
|
-
},
|
|
253
|
-
{
|
|
254
|
-
label: req.__("Role to access"),
|
|
255
|
-
key: (row) => editPageRoleForm(row, roles, req),
|
|
256
|
-
},
|
|
257
|
-
{
|
|
258
|
-
label: req.__("Edit"),
|
|
259
|
-
key: (r) => link(`/pageedit/edit/${r.name}`, req.__("Edit")),
|
|
260
|
-
},
|
|
261
|
-
{
|
|
262
|
-
label: "",
|
|
263
|
-
key: (r) => page_dropdown(r, req),
|
|
264
|
-
},
|
|
265
|
-
],
|
|
266
|
-
rows,
|
|
267
|
-
{ hover: true }
|
|
268
|
-
),
|
|
269
|
-
a(
|
|
270
|
-
{
|
|
271
|
-
href: `/pageedit/new`,
|
|
272
|
-
class: "btn btn-primary",
|
|
273
|
-
},
|
|
274
|
-
req.__("Create page")
|
|
275
|
-
)
|
|
276
|
-
);
|
|
277
|
-
};
|
|
278
|
-
|
|
279
177
|
/**
|
|
280
178
|
* Root pages configuration Form
|
|
281
179
|
* Allows to configure root page for each role
|
|
@@ -287,9 +185,8 @@ const getPageList = (rows, roles, req) => {
|
|
|
287
185
|
const getRootPageForm = (pages, roles, req) => {
|
|
288
186
|
const form = new Form({
|
|
289
187
|
action: "/pageedit/set_root_page",
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
onChange: "remove_outline(this)",
|
|
188
|
+
noSubmitButton: true,
|
|
189
|
+
onChange: "saveAndContinue(this)",
|
|
293
190
|
blurb: req.__(
|
|
294
191
|
"The root page is the page that is served when the user visits the home location (/). This can be set for each user role."
|
|
295
192
|
),
|
|
@@ -335,7 +232,16 @@ router.get(
|
|
|
335
232
|
type: "card",
|
|
336
233
|
title: req.__("Your pages"),
|
|
337
234
|
class: "mt-0",
|
|
338
|
-
contents:
|
|
235
|
+
contents: div(
|
|
236
|
+
getPageList(pages, roles, req),
|
|
237
|
+
a(
|
|
238
|
+
{
|
|
239
|
+
href: `/pageedit/new`,
|
|
240
|
+
class: "btn btn-primary",
|
|
241
|
+
},
|
|
242
|
+
req.__("Create page")
|
|
243
|
+
)
|
|
244
|
+
),
|
|
339
245
|
},
|
|
340
246
|
{
|
|
341
247
|
type: "card",
|
package/routes/plugins.js
CHANGED
|
@@ -455,7 +455,7 @@ const store_actions_dropdown = (req) =>
|
|
|
455
455
|
{
|
|
456
456
|
class: "dropdown-item",
|
|
457
457
|
href: `/plugins/upgrade`,
|
|
458
|
-
onClick: `notifyAlert('Upgrading modules...', true)`,
|
|
458
|
+
onClick: `notifyAlert('${req.__("Upgrading modules...")}', true)`,
|
|
459
459
|
},
|
|
460
460
|
'<i class="far fa-arrow-alt-circle-up"></i> ' +
|
|
461
461
|
req.__("Upgrade installed modules")
|
|
@@ -551,7 +551,7 @@ router.get(
|
|
|
551
551
|
const { name } = req.params;
|
|
552
552
|
const plugin = await Plugin.findOne({ name: decodeURIComponent(name) });
|
|
553
553
|
if (!plugin) {
|
|
554
|
-
req.flash("warning", "
|
|
554
|
+
req.flash("warning", req.__("Module not found"));
|
|
555
555
|
res.redirect("/plugins");
|
|
556
556
|
return;
|
|
557
557
|
}
|
|
@@ -792,7 +792,7 @@ router.get(
|
|
|
792
792
|
pkgjson = require(path.join(mod.location, "package.json"));
|
|
793
793
|
|
|
794
794
|
if (!plugin_db) {
|
|
795
|
-
req.flash("warning", "
|
|
795
|
+
req.flash("warning", "Module not found");
|
|
796
796
|
res.redirect("/plugins");
|
|
797
797
|
return;
|
|
798
798
|
}
|
|
@@ -817,7 +817,7 @@ router.get(
|
|
|
817
817
|
),
|
|
818
818
|
mod.plugin_module.dependencies
|
|
819
819
|
? tr(
|
|
820
|
-
th(req.__("
|
|
820
|
+
th(req.__("Module dependencies")),
|
|
821
821
|
td(
|
|
822
822
|
mod.plugin_module.dependencies.map((d) =>
|
|
823
823
|
span({ class: "badge bg-primary me-1" }, d)
|
|
@@ -933,7 +933,7 @@ router.get(
|
|
|
933
933
|
|
|
934
934
|
const plugin = await Plugin.findOne({ name });
|
|
935
935
|
await plugin.upgrade_version((p, f) => load_plugins.loadPlugin(p, f));
|
|
936
|
-
req.flash("success", req.__(`
|
|
936
|
+
req.flash("success", req.__(`Module up-to-date`));
|
|
937
937
|
|
|
938
938
|
res.redirect(`/plugins/info/${plugin.name}`);
|
|
939
939
|
})
|
|
@@ -954,7 +954,7 @@ router.post(
|
|
|
954
954
|
if (schema !== db.connectObj.default_schema) {
|
|
955
955
|
req.flash(
|
|
956
956
|
"error",
|
|
957
|
-
req.__(`Only store
|
|
957
|
+
req.__(`Only store modules can be installed on tenant instances`)
|
|
958
958
|
);
|
|
959
959
|
res.redirect(`/plugins`);
|
|
960
960
|
} else {
|
|
@@ -963,12 +963,12 @@ router.post(
|
|
|
963
963
|
plugin,
|
|
964
964
|
schema === db.connectObj.default_schema || plugin.source === "github"
|
|
965
965
|
);
|
|
966
|
-
req.flash("success", req.__(`
|
|
966
|
+
req.flash("success", req.__(`Module %s installed`, plugin.name));
|
|
967
967
|
res.redirect(`/plugins`);
|
|
968
968
|
} catch (e) {
|
|
969
969
|
req.flash("error", `${e.message}`);
|
|
970
970
|
const form = pluginForm(req, plugin);
|
|
971
|
-
res.sendWrap(req.__(`Edit
|
|
971
|
+
res.sendWrap(req.__(`Edit Module`), renderForm(form, req.csrfToken()));
|
|
972
972
|
}
|
|
973
973
|
}
|
|
974
974
|
})
|
|
@@ -988,7 +988,7 @@ router.post(
|
|
|
988
988
|
|
|
989
989
|
const plugin = await Plugin.findOne({ name: decodeURIComponent(name) });
|
|
990
990
|
if (!plugin) {
|
|
991
|
-
req.flash("warning", "
|
|
991
|
+
req.flash("warning", "Module not found");
|
|
992
992
|
res.redirect("/plugins");
|
|
993
993
|
return;
|
|
994
994
|
}
|
|
@@ -998,11 +998,11 @@ router.post(
|
|
|
998
998
|
getState().getConfig("development_mode", false)
|
|
999
999
|
) {
|
|
1000
1000
|
await plugin.delete();
|
|
1001
|
-
req.flash("success", req.__(`
|
|
1001
|
+
req.flash("success", req.__(`Module %s removed.`, plugin.name));
|
|
1002
1002
|
} else {
|
|
1003
1003
|
req.flash(
|
|
1004
1004
|
"error",
|
|
1005
|
-
req.__(`Cannot remove
|
|
1005
|
+
req.__(`Cannot remove module: views %s depend on it`, depviews.join())
|
|
1006
1006
|
);
|
|
1007
1007
|
}
|
|
1008
1008
|
res.redirect(`/plugins`);
|
|
@@ -1025,7 +1025,7 @@ router.post(
|
|
|
1025
1025
|
if (!plugin) {
|
|
1026
1026
|
req.flash(
|
|
1027
1027
|
"error",
|
|
1028
|
-
req.__(`
|
|
1028
|
+
req.__(`Module %s not found`, text(decodeURIComponent(name)))
|
|
1029
1029
|
);
|
|
1030
1030
|
res.redirect(`/plugins`);
|
|
1031
1031
|
return;
|
|
@@ -1034,7 +1034,7 @@ router.post(
|
|
|
1034
1034
|
if (!isRoot && plugin.unsafe) {
|
|
1035
1035
|
req.flash(
|
|
1036
1036
|
"error",
|
|
1037
|
-
req.__("Cannot install unsafe
|
|
1037
|
+
req.__("Cannot install unsafe modules on subdomain tenants")
|
|
1038
1038
|
);
|
|
1039
1039
|
res.redirect(`/plugins`);
|
|
1040
1040
|
return;
|
|
@@ -1047,14 +1047,14 @@ router.post(
|
|
|
1047
1047
|
req.flash(
|
|
1048
1048
|
"success",
|
|
1049
1049
|
req.__(
|
|
1050
|
-
`
|
|
1050
|
+
`Module %s installed, please complete configuration.`,
|
|
1051
1051
|
plugin_db.name
|
|
1052
1052
|
)
|
|
1053
1053
|
);
|
|
1054
1054
|
await sleep(1000); // Allow other workers to load this plugin
|
|
1055
1055
|
res.redirect(`/plugins/configure/${plugin_db.name}`);
|
|
1056
1056
|
} else {
|
|
1057
|
-
req.flash("success", req.__(`
|
|
1057
|
+
req.flash("success", req.__(`Module %s installed`, plugin.name));
|
|
1058
1058
|
res.redirect(`/plugins`);
|
|
1059
1059
|
}
|
|
1060
1060
|
})
|
package/routes/tables.js
CHANGED
|
@@ -56,6 +56,7 @@ const {
|
|
|
56
56
|
} = require("@saltcorn/data/models/discovery");
|
|
57
57
|
const { getState } = require("@saltcorn/data/db/state");
|
|
58
58
|
const { cardHeaderTabs } = require("@saltcorn/markup/layout_utils");
|
|
59
|
+
const { tablesList } = require("./common_lists");
|
|
59
60
|
|
|
60
61
|
/**
|
|
61
62
|
* @type {object}
|
|
@@ -129,7 +130,7 @@ const tableForm = async (table, req) => {
|
|
|
129
130
|
{
|
|
130
131
|
label: req.__("Minimum role to read"),
|
|
131
132
|
sublabel: req.__(
|
|
132
|
-
"User must have this role or higher to read rows from the table"
|
|
133
|
+
"User must have this role or higher to read rows from the table, unless they are the owner"
|
|
133
134
|
),
|
|
134
135
|
name: "min_role_read",
|
|
135
136
|
input_type: "select",
|
|
@@ -143,7 +144,7 @@ const tableForm = async (table, req) => {
|
|
|
143
144
|
name: "min_role_write",
|
|
144
145
|
input_type: "select",
|
|
145
146
|
sublabel: req.__(
|
|
146
|
-
"User must have this role or higher to edit or create new rows in the table"
|
|
147
|
+
"User must have this role or higher to edit or create new rows in the table, unless they are the owner"
|
|
147
148
|
),
|
|
148
149
|
options: roleOptions,
|
|
149
150
|
},
|
|
@@ -888,7 +889,6 @@ router.post(
|
|
|
888
889
|
if (rest.ownership_field_id === "_formula") {
|
|
889
890
|
rest.ownership_field_id = null;
|
|
890
891
|
const fmlValidRes = expressionValidator(rest.ownership_formula);
|
|
891
|
-
console.log({ fmlValidRes });
|
|
892
892
|
if (typeof fmlValidRes === "string") {
|
|
893
893
|
req.flash(
|
|
894
894
|
"error",
|
|
@@ -1011,44 +1011,8 @@ router.get(
|
|
|
1011
1011
|
const rows = await Table.find_with_external({}, { orderBy: "name" });
|
|
1012
1012
|
const roles = await User.get_roles();
|
|
1013
1013
|
const getRole = (rid) => roles.find((r) => r.id === rid).role;
|
|
1014
|
-
const mainCard =
|
|
1015
|
-
rows.length > 0
|
|
1016
|
-
? mkTable(
|
|
1017
|
-
[
|
|
1018
|
-
{
|
|
1019
|
-
label: req.__("Name"),
|
|
1020
|
-
key: (r) => link(`/table/${r.id || r.name}`, text(r.name)),
|
|
1021
|
-
},
|
|
1022
|
-
{
|
|
1023
|
-
label: "",
|
|
1024
|
-
key: (r) => tableBadges(r, req),
|
|
1025
|
-
},
|
|
1026
|
-
{
|
|
1027
|
-
label: req.__("Access Read/Write"),
|
|
1028
|
-
key: (t) =>
|
|
1029
|
-
t.external
|
|
1030
|
-
? `${getRole(t.min_role_read)} (read only)`
|
|
1031
|
-
: `${getRole(t.min_role_read)}/${getRole(
|
|
1032
|
-
t.min_role_write
|
|
1033
|
-
)}`,
|
|
1034
|
-
},
|
|
1035
|
-
{
|
|
1036
|
-
label: req.__("Delete"),
|
|
1037
|
-
key: (r) =>
|
|
1038
|
-
r.name === "users" || r.external
|
|
1039
|
-
? ""
|
|
1040
|
-
: post_delete_btn(`/table/delete/${r.id}`, req, r.name),
|
|
1041
|
-
},
|
|
1042
|
-
],
|
|
1043
|
-
rows,
|
|
1044
|
-
{ hover: true }
|
|
1045
|
-
)
|
|
1046
|
-
: div(
|
|
1047
|
-
h4(req.__("No tables defined")),
|
|
1048
|
-
p(req.__("Tables hold collections of similar data"))
|
|
1049
|
-
);
|
|
1014
|
+
const mainCard = await tablesList(rows, req);
|
|
1050
1015
|
const createCard = div(
|
|
1051
|
-
h5(req.__("Create table")),
|
|
1052
1016
|
a(
|
|
1053
1017
|
{ href: `/table/new`, class: "btn btn-primary mt-1 me-3" },
|
|
1054
1018
|
i({ class: "fas fa-plus-square me-1" }),
|
|
@@ -1064,8 +1028,13 @@ router.get(
|
|
|
1064
1028
|
),
|
|
1065
1029
|
!db.isSQLite &&
|
|
1066
1030
|
a(
|
|
1067
|
-
{
|
|
1031
|
+
{
|
|
1032
|
+
href: `/table/discover`,
|
|
1033
|
+
class: "btn btn-secondary mt-1",
|
|
1034
|
+
title: req.__("Discover tables that are already in the Database, but not known to Saltcorn"),
|
|
1035
|
+
},
|
|
1068
1036
|
i({ class: "fas fa-map-signs me-1" }),
|
|
1037
|
+
|
|
1069
1038
|
req.__("Discover tables")
|
|
1070
1039
|
)
|
|
1071
1040
|
);
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
const {
|
|
2
|
+
a,
|
|
3
|
+
div,
|
|
4
|
+
text,
|
|
5
|
+
button,
|
|
6
|
+
i,
|
|
7
|
+
form,
|
|
8
|
+
select,
|
|
9
|
+
option,
|
|
10
|
+
label,
|
|
11
|
+
} = require("@saltcorn/markup/tags");
|
|
12
|
+
|
|
13
|
+
const Tag = require("@saltcorn/data/models/tag");
|
|
14
|
+
const TagEntry = require("@saltcorn/data/models/tag_entry");
|
|
15
|
+
const Router = require("express-promise-router");
|
|
16
|
+
|
|
17
|
+
const { isAdmin, error_catcher, csrfField } = require("./utils");
|
|
18
|
+
|
|
19
|
+
const Table = require("@saltcorn/data/models/table");
|
|
20
|
+
const View = require("@saltcorn/data/models/view");
|
|
21
|
+
const Page = require("@saltcorn/data/models/page");
|
|
22
|
+
const Trigger = require("@saltcorn/data/models/trigger");
|
|
23
|
+
|
|
24
|
+
const router = new Router();
|
|
25
|
+
module.exports = router;
|
|
26
|
+
|
|
27
|
+
const buildFields = (entryType, formOptions, req) => {
|
|
28
|
+
return Object.entries(formOptions).map(([type, list]) => {
|
|
29
|
+
return div(
|
|
30
|
+
{ class: "form-group row" },
|
|
31
|
+
div({ class: "col-sm-2" }, label("type")),
|
|
32
|
+
div(
|
|
33
|
+
{ class: "col-sm-10" },
|
|
34
|
+
select(
|
|
35
|
+
{ name: "ids", class: "form-control form-select", multiple: true },
|
|
36
|
+
list.map((entry) => {
|
|
37
|
+
return option({ value: entry.id, label: entry.name });
|
|
38
|
+
})
|
|
39
|
+
)
|
|
40
|
+
),
|
|
41
|
+
div(
|
|
42
|
+
{ class: "col-sm-12" },
|
|
43
|
+
button({ type: "submit", class: "btn btn-primary" }, req.__("Save"))
|
|
44
|
+
)
|
|
45
|
+
);
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const buildForm = (entryType, tag_id, formOptions, req) => {
|
|
50
|
+
return form(
|
|
51
|
+
{ action: `/tag-entries/add/${entryType}/${tag_id}`, method: "post" },
|
|
52
|
+
csrfField(req),
|
|
53
|
+
buildFields(entryType, formOptions, req)
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const formOptions = async (type, tag_id) => {
|
|
58
|
+
const tag = await Tag.findOne({ id: tag_id });
|
|
59
|
+
switch (type) {
|
|
60
|
+
case "tables": {
|
|
61
|
+
const ids = await tag.getTableIds();
|
|
62
|
+
return {
|
|
63
|
+
tables: (await Table.find()).filter(
|
|
64
|
+
(value) => ids.indexOf(value.id) === -1
|
|
65
|
+
),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
case "views": {
|
|
69
|
+
const ids = await tag.getViewIds();
|
|
70
|
+
return {
|
|
71
|
+
views: (await View.find()).filter(
|
|
72
|
+
(value) => ids.indexOf(value.id) === -1
|
|
73
|
+
),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
case "pages": {
|
|
77
|
+
const ids = await tag.getPageIds();
|
|
78
|
+
return {
|
|
79
|
+
pages: (await Page.find()).filter(
|
|
80
|
+
(value) => ids.indexOf(value.id) === -1
|
|
81
|
+
),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
case "trigger": {
|
|
85
|
+
const ids = await tag.getTriggerIds();
|
|
86
|
+
return {
|
|
87
|
+
trigger: (await Trigger.find()).filter(
|
|
88
|
+
(value) => ids.indexOf(value.id) === -1
|
|
89
|
+
),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
router.get(
|
|
96
|
+
"/add/:entry_type/:tag_id",
|
|
97
|
+
isAdmin,
|
|
98
|
+
error_catcher(async (req, res) => {
|
|
99
|
+
const { entry_type, tag_id } = req.params;
|
|
100
|
+
res.sendWrap(req.__("Add %s to tag"), {
|
|
101
|
+
above: [
|
|
102
|
+
{
|
|
103
|
+
type: "breadcrumbs",
|
|
104
|
+
crumbs: [{ text: `Tag entry` }],
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
type: "card",
|
|
108
|
+
title: req.__(`Add entries to tag`),
|
|
109
|
+
contents: buildForm(
|
|
110
|
+
entry_type,
|
|
111
|
+
tag_id,
|
|
112
|
+
await formOptions(entry_type, tag_id),
|
|
113
|
+
req
|
|
114
|
+
),
|
|
115
|
+
},
|
|
116
|
+
],
|
|
117
|
+
});
|
|
118
|
+
})
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
const idField = (entryType) => {
|
|
122
|
+
switch (entryType) {
|
|
123
|
+
case "tables": {
|
|
124
|
+
return "table_id";
|
|
125
|
+
}
|
|
126
|
+
case "views": {
|
|
127
|
+
return "view_id";
|
|
128
|
+
}
|
|
129
|
+
case "pages": {
|
|
130
|
+
return "page_id";
|
|
131
|
+
}
|
|
132
|
+
case "trigger": {
|
|
133
|
+
return "trigger_id";
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return null;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
router.post(
|
|
140
|
+
"/add/:entry_type/:tag_id",
|
|
141
|
+
isAdmin,
|
|
142
|
+
error_catcher(async (req, res) => {
|
|
143
|
+
const { entry_type, tag_id } = req.params;
|
|
144
|
+
const { ids } = req.body;
|
|
145
|
+
if (!ids) {
|
|
146
|
+
req.flash("error", req.__("Please select at least one item"));
|
|
147
|
+
return res.redirect(`/tag-entries/add/${entry_type}/${tag_id}`);
|
|
148
|
+
}
|
|
149
|
+
const fieldName = idField(entry_type);
|
|
150
|
+
const tag = await Tag.findOne({ id: tag_id });
|
|
151
|
+
for (const id of ids) {
|
|
152
|
+
await tag.addEntry({ [fieldName]: id });
|
|
153
|
+
}
|
|
154
|
+
res.redirect(`/tag/${tag_id}?show_list=${entry_type}`);
|
|
155
|
+
})
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
router.post(
|
|
159
|
+
"/remove/:entry_type/:entry_id/:tag_id",
|
|
160
|
+
isAdmin,
|
|
161
|
+
error_catcher(async (req, res) => {
|
|
162
|
+
const { tag_id, entry_type, entry_id } = req.params;
|
|
163
|
+
const fieldName = idField(entry_type);
|
|
164
|
+
const entry = await TagEntry.findOne({ tag_id, [fieldName]: entry_id });
|
|
165
|
+
entry[fieldName] = undefined;
|
|
166
|
+
if (entry.isEmpty()) {
|
|
167
|
+
await entry.delete();
|
|
168
|
+
} else {
|
|
169
|
+
await TagEntry.update(entry.id, { [fieldName]: null });
|
|
170
|
+
}
|
|
171
|
+
res.redirect(`/tag/${tag_id}?show_list=${entry_type}`);
|
|
172
|
+
})
|
|
173
|
+
);
|