@saltcorn/server 0.7.3 → 0.7.4-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/auth/admin.js +2 -1
- package/auth/routes.js +80 -92
- package/errors.js +51 -48
- package/locales/en.json +47 -2
- package/locales/it.json +2 -1
- package/locales/ru.json +42 -6
- package/locales/zh.json +1 -1
- package/markup/admin.js +15 -1
- package/markup/plugin-store.js +5 -5
- package/package.json +7 -7
- package/public/jquery-menu-editor.min.js +1 -1
- package/public/saltcorn-builder.css +75 -0
- package/public/saltcorn-common.js +24 -9
- package/public/saltcorn.css +28 -1
- package/public/saltcorn.js +9 -7
- package/routes/actions.js +2 -39
- package/routes/admin.js +375 -90
- package/routes/api.js +9 -1
- package/routes/common_lists.js +419 -0
- package/routes/fields.js +34 -19
- package/routes/homepage.js +60 -60
- package/routes/index.js +4 -0
- package/routes/menu.js +65 -4
- package/routes/packs.js +4 -4
- package/routes/page.js +5 -1
- package/routes/pageedit.js +13 -98
- package/routes/plugins.js +116 -118
- package/routes/settings.js +3 -3
- package/routes/tables.js +158 -193
- package/routes/tag_entries.js +173 -0
- package/routes/tags.js +266 -0
- package/routes/tenant.js +27 -27
- package/routes/utils.js +4 -0
- package/routes/view.js +18 -1
- package/routes/viewedit.js +22 -132
- package/serve.js +54 -38
- package/tests/admin.test.js +1 -1
- package/tests/api.test.js +17 -0
- package/tests/clientjs.test.js +11 -1
- package/tests/plugins.test.js +1 -1
- package/tests/viewedit.test.js +1 -1
- package/wrapper.js +57 -55
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}
|
|
@@ -88,33 +89,33 @@ const tableForm = async (table, req) => {
|
|
|
88
89
|
fields: [
|
|
89
90
|
...(!table.external
|
|
90
91
|
? [
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
92
|
+
{
|
|
93
|
+
label: req.__("Ownership field"),
|
|
94
|
+
name: "ownership_field_id",
|
|
95
|
+
sublabel: req.__(
|
|
96
|
+
"The user referred to in this field will be the owner of the row"
|
|
97
|
+
),
|
|
98
|
+
input_type: "select",
|
|
99
|
+
options: [
|
|
100
|
+
{ value: "", label: req.__("None") },
|
|
101
|
+
...userFields,
|
|
102
|
+
{ value: "_formula", label: req.__("Formula") },
|
|
103
|
+
],
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: "ownership_formula",
|
|
107
|
+
label: req.__("Ownership formula"),
|
|
108
|
+
validator: expressionValidator,
|
|
109
|
+
type: "String",
|
|
110
|
+
class: "validate-expression",
|
|
111
|
+
sublabel:
|
|
112
|
+
req.__("User is treated as owner if true. In scope: ") +
|
|
113
|
+
["user", ...fields.map((f) => f.name)]
|
|
114
|
+
.map((fn) => code(fn))
|
|
115
|
+
.join(", "),
|
|
116
|
+
showIf: { ownership_field_id: "_formula" },
|
|
117
|
+
},
|
|
118
|
+
]
|
|
118
119
|
: []),
|
|
119
120
|
// description of table
|
|
120
121
|
{
|
|
@@ -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",
|
|
@@ -138,24 +139,24 @@ const tableForm = async (table, req) => {
|
|
|
138
139
|
...(table.external
|
|
139
140
|
? []
|
|
140
141
|
: [
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
142
|
+
{
|
|
143
|
+
label: req.__("Minimum role to write"),
|
|
144
|
+
name: "min_role_write",
|
|
145
|
+
input_type: "select",
|
|
146
|
+
sublabel: req.__(
|
|
147
|
+
"User must have this role or higher to edit or create new rows in the table, unless they are the owner"
|
|
148
|
+
),
|
|
149
|
+
options: roleOptions,
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
label: req.__("Version history"),
|
|
153
|
+
sublabel: req.__(
|
|
154
|
+
"Version history allows to track table data changes"
|
|
155
|
+
),
|
|
156
|
+
name: "versioned",
|
|
157
|
+
type: "Bool",
|
|
158
|
+
},
|
|
159
|
+
]),
|
|
159
160
|
],
|
|
160
161
|
});
|
|
161
162
|
if (table) {
|
|
@@ -222,11 +223,11 @@ const discoverForm = (tables, req) => {
|
|
|
222
223
|
blurb:
|
|
223
224
|
tables.length > 0
|
|
224
225
|
? req.__(
|
|
225
|
-
|
|
226
|
-
|
|
226
|
+
"The following tables in your database can be imported into Saltcorn:"
|
|
227
|
+
)
|
|
227
228
|
: req.__(
|
|
228
|
-
|
|
229
|
-
|
|
229
|
+
"There are no tables in the database that can be imported into Saltcorn."
|
|
230
|
+
),
|
|
230
231
|
submitLabel: req.__("Import"),
|
|
231
232
|
fields: tables.map((t) => ({
|
|
232
233
|
name: t.table_name,
|
|
@@ -579,11 +580,11 @@ router.get(
|
|
|
579
580
|
key: (r) =>
|
|
580
581
|
r.type === "Key"
|
|
581
582
|
? `Key to ` +
|
|
582
|
-
|
|
583
|
+
a({ href: `/table/${r.reftable_name}` }, r.reftable_name)
|
|
583
584
|
: (r.type && r.type.name) ||
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
585
|
+
r.type ||
|
|
586
|
+
r.typename +
|
|
587
|
+
span({ class: "badge bg-danger ms-1" }, "Unknown type"),
|
|
587
588
|
},
|
|
588
589
|
{
|
|
589
590
|
label: "",
|
|
@@ -597,23 +598,23 @@ router.get(
|
|
|
597
598
|
...(table.external
|
|
598
599
|
? []
|
|
599
600
|
: [
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
601
|
+
{
|
|
602
|
+
label: req.__("Edit"),
|
|
603
|
+
key: (r) => link(`/field/${r.id}`, req.__("Edit")),
|
|
604
|
+
},
|
|
605
|
+
]),
|
|
605
606
|
...(table.external || db.isSQLite
|
|
606
607
|
? []
|
|
607
608
|
: [
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
609
|
+
{
|
|
610
|
+
label: req.__("Delete"),
|
|
611
|
+
key: (r) =>
|
|
612
|
+
(table.name === "users" && r.name === "email") ||
|
|
612
613
|
r.primary_key
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
614
|
+
? ""
|
|
615
|
+
: post_delete_btn(`/field/delete/${r.id}`, req, r.name),
|
|
616
|
+
},
|
|
617
|
+
]),
|
|
617
618
|
],
|
|
618
619
|
fields,
|
|
619
620
|
{ hover: true }
|
|
@@ -622,17 +623,17 @@ router.get(
|
|
|
622
623
|
tableHtml,
|
|
623
624
|
inbound_refs.length > 0
|
|
624
625
|
? req.__("Inbound keys: ") +
|
|
625
|
-
|
|
626
|
-
|
|
626
|
+
inbound_refs.map((tnm) => link(`/table/${tnm}`, tnm)).join(", ") +
|
|
627
|
+
"<br>"
|
|
627
628
|
: "",
|
|
628
629
|
!table.external &&
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
630
|
+
a(
|
|
631
|
+
{
|
|
632
|
+
href: `/field/new/${table.id}`,
|
|
633
|
+
class: "btn btn-primary add-field mt-2",
|
|
634
|
+
},
|
|
635
|
+
req.__("Add field")
|
|
636
|
+
),
|
|
636
637
|
];
|
|
637
638
|
}
|
|
638
639
|
var viewCard;
|
|
@@ -645,7 +646,7 @@ router.get(
|
|
|
645
646
|
viewCardContents = mkTable(
|
|
646
647
|
[
|
|
647
648
|
{ label: req.__("Name"), key: "name" },
|
|
648
|
-
{ label: req.__("
|
|
649
|
+
{ label: req.__("Pattern"), key: "viewtemplate" },
|
|
649
650
|
{
|
|
650
651
|
label: req.__("Run"),
|
|
651
652
|
key: (r) =>
|
|
@@ -704,8 +705,8 @@ router.get(
|
|
|
704
705
|
table.name === "users"
|
|
705
706
|
? `/useradmin/`
|
|
706
707
|
: fields.length === 1
|
|
707
|
-
|
|
708
|
-
|
|
708
|
+
? `javascript:;` // Fix problem with edition of table with only one column ID / Primary Key
|
|
709
|
+
: `/list/${table.name}`,
|
|
709
710
|
},
|
|
710
711
|
i({ class: "fas fa-2x fa-edit" }),
|
|
711
712
|
"<br/>",
|
|
@@ -725,74 +726,74 @@ router.get(
|
|
|
725
726
|
)
|
|
726
727
|
),
|
|
727
728
|
!table.external &&
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
729
|
+
div(
|
|
730
|
+
{ class: "mx-auto" },
|
|
731
|
+
form(
|
|
732
|
+
{
|
|
733
|
+
method: "post",
|
|
734
|
+
action: `/table/upload_to_table/${table.name}`,
|
|
735
|
+
encType: "multipart/form-data",
|
|
736
|
+
},
|
|
737
|
+
input({ type: "hidden", name: "_csrf", value: req.csrfToken() }),
|
|
738
|
+
label(
|
|
739
|
+
{ class: "btn-link", for: "upload_to_table" },
|
|
740
|
+
i({ class: "fas fa-2x fa-upload" }),
|
|
741
|
+
"<br/>",
|
|
742
|
+
req.__("Upload CSV")
|
|
743
|
+
),
|
|
744
|
+
input({
|
|
745
|
+
id: "upload_to_table",
|
|
746
|
+
name: "file",
|
|
747
|
+
type: "file",
|
|
748
|
+
accept: "text/csv,.csv",
|
|
749
|
+
onchange: "this.form.submit();",
|
|
750
|
+
})
|
|
751
|
+
)
|
|
752
|
+
),
|
|
752
753
|
// only if table is not external
|
|
753
754
|
!table.external &&
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
755
|
+
div(
|
|
756
|
+
{ class: "mx-auto" },
|
|
757
|
+
settingsDropdown(`dataMenuButton`, [
|
|
758
|
+
a(
|
|
759
|
+
{
|
|
760
|
+
class: "dropdown-item",
|
|
761
|
+
href: `/table/constraints/${table.id}`,
|
|
762
|
+
},
|
|
763
|
+
'<i class="fas fa-ban"></i> ' + req.__("Constraints")
|
|
764
|
+
),
|
|
765
|
+
// rename table doesnt supported for sqlite
|
|
766
|
+
!db.isSQLite &&
|
|
767
|
+
table.name !== "users" &&
|
|
768
|
+
a(
|
|
769
|
+
{
|
|
770
|
+
class: "dropdown-item",
|
|
771
|
+
href: `/table/rename/${table.id}`,
|
|
772
|
+
},
|
|
773
|
+
'<i class="fas fa-edit"></i> ' + req.__("Rename table")
|
|
774
|
+
),
|
|
775
|
+
post_dropdown_item(
|
|
776
|
+
`/table/recalc-stored/${table.name}`,
|
|
777
|
+
'<i class="fas fa-sync"></i> ' +
|
|
778
|
+
req.__("Recalculate stored fields"),
|
|
779
|
+
req
|
|
780
|
+
),
|
|
781
|
+
post_dropdown_item(
|
|
782
|
+
`/table/delete-all-rows/${table.name}`,
|
|
783
|
+
'<i class="far fa-trash-alt"></i> ' +
|
|
784
|
+
req.__("Delete all rows"),
|
|
785
|
+
req,
|
|
786
|
+
true
|
|
787
|
+
),
|
|
788
|
+
table.name !== "users" &&
|
|
789
|
+
post_dropdown_item(
|
|
790
|
+
`/table/forget-table/${table.id}`,
|
|
791
|
+
'<i class="fas fa-recycle"></i> ' + req.__("Forget table"),
|
|
792
|
+
req,
|
|
793
|
+
true
|
|
794
|
+
),
|
|
795
|
+
])
|
|
796
|
+
)
|
|
796
797
|
);
|
|
797
798
|
// add table form
|
|
798
799
|
if (table.ownership_formula && !table.ownership_field_id)
|
|
@@ -815,12 +816,12 @@ router.get(
|
|
|
815
816
|
},
|
|
816
817
|
...(fields.length > 0
|
|
817
818
|
? [
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
819
|
+
{
|
|
820
|
+
type: "card",
|
|
821
|
+
title: req.__("Table data"),
|
|
822
|
+
contents: dataCard,
|
|
823
|
+
},
|
|
824
|
+
]
|
|
824
825
|
: []),
|
|
825
826
|
...(viewCard ? [viewCard] : []),
|
|
826
827
|
{
|
|
@@ -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,42 +1011,7 @@ 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
1016
|
h5(req.__("Create table")),
|
|
1052
1017
|
a(
|
|
@@ -1063,11 +1028,11 @@ router.get(
|
|
|
1063
1028
|
req.__("Create from CSV upload")
|
|
1064
1029
|
),
|
|
1065
1030
|
!db.isSQLite &&
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1031
|
+
a(
|
|
1032
|
+
{ href: `/table/discover`, class: "btn btn-secondary mt-1" },
|
|
1033
|
+
i({ class: "fas fa-map-signs me-1" }),
|
|
1034
|
+
req.__("Discover tables")
|
|
1035
|
+
)
|
|
1071
1036
|
);
|
|
1072
1037
|
res.sendWrap(req.__("Tables"), {
|
|
1073
1038
|
above: [
|
|
@@ -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: `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 on 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
|
+
);
|