@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/app.js
CHANGED
|
@@ -85,6 +85,8 @@ const getApp = async (opts = {}) => {
|
|
|
85
85
|
const development_mode = getState().getConfig("development_mode", false);
|
|
86
86
|
// switch on sql logging - but it was initiated before???
|
|
87
87
|
if (getState().getConfig("log_sql", false)) db.set_sql_logging();
|
|
88
|
+
// for multi-tenant with localhost, we need 1 instead of the default of 2
|
|
89
|
+
if (opts.subdomainOffset) app.set("subdomain offset", opts.subdomainOffset);
|
|
88
90
|
|
|
89
91
|
// https://www.npmjs.com/package/helmet
|
|
90
92
|
// helmet is secure app by adding HTTP headers
|
|
@@ -120,12 +122,10 @@ const getApp = async (opts = {}) => {
|
|
|
120
122
|
app.use(passport.initialize());
|
|
121
123
|
app.use(passport.authenticate(["jwt", "session"]));
|
|
122
124
|
app.use((req, res, next) => {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
next();
|
|
128
|
-
});
|
|
125
|
+
// no jwt and session id at the same time
|
|
126
|
+
if (!(jwt_extractor(req) && req.cookies && req.cookies["connect.sid"]))
|
|
127
|
+
next();
|
|
128
|
+
});
|
|
129
129
|
app.use(flash());
|
|
130
130
|
|
|
131
131
|
//static serving
|
|
@@ -168,6 +168,15 @@ const getApp = async (opts = {}) => {
|
|
|
168
168
|
}
|
|
169
169
|
)
|
|
170
170
|
);
|
|
171
|
+
app.use(
|
|
172
|
+
`/static_assets/${version_tag}`,
|
|
173
|
+
express.static(
|
|
174
|
+
path.dirname(require.resolve("@saltcorn/filemanager/package.json")) + "/public/build",
|
|
175
|
+
{
|
|
176
|
+
maxAge: development_mode ? 0 : "100d",
|
|
177
|
+
}
|
|
178
|
+
)
|
|
179
|
+
);
|
|
171
180
|
|
|
172
181
|
passport.use(
|
|
173
182
|
"local",
|
|
@@ -225,8 +234,9 @@ const getApp = async (opts = {}) => {
|
|
|
225
234
|
})
|
|
226
235
|
);
|
|
227
236
|
passport.use(
|
|
228
|
-
new JwtStrategy(jwtOpts, (jwt_payload, done) => {
|
|
229
|
-
|
|
237
|
+
new JwtStrategy(jwtOpts, async (jwt_payload, done) => {
|
|
238
|
+
const userCheck = async () => {
|
|
239
|
+
const u = await User.findOne({ email: jwt_payload.sub });
|
|
230
240
|
if (
|
|
231
241
|
u &&
|
|
232
242
|
u.last_mobile_login &&
|
|
@@ -242,7 +252,16 @@ const getApp = async (opts = {}) => {
|
|
|
242
252
|
} else {
|
|
243
253
|
return done(null, { role_id: 10 });
|
|
244
254
|
}
|
|
245
|
-
}
|
|
255
|
+
};
|
|
256
|
+
if (
|
|
257
|
+
db.is_it_multi_tenant() &&
|
|
258
|
+
jwt_payload.tenant?.length > 0 &&
|
|
259
|
+
jwt_payload.tenant !== db.connectObj.default_schema
|
|
260
|
+
) {
|
|
261
|
+
return await db.runWithTenant(jwt_payload.tenant, userCheck);
|
|
262
|
+
} else {
|
|
263
|
+
return await userCheck();
|
|
264
|
+
}
|
|
246
265
|
})
|
|
247
266
|
);
|
|
248
267
|
passport.use(
|
|
@@ -259,6 +278,12 @@ const getApp = async (opts = {}) => {
|
|
|
259
278
|
passport.deserializeUser(function (user, done) {
|
|
260
279
|
done(null, user);
|
|
261
280
|
});
|
|
281
|
+
app.use(function (req, res, next) {
|
|
282
|
+
if (req.headers["x-saltcorn-client"] === "mobile-app") {
|
|
283
|
+
req.smr = true; // saltcorn-mobile-request
|
|
284
|
+
}
|
|
285
|
+
return next();
|
|
286
|
+
});
|
|
262
287
|
app.use(setTenant);
|
|
263
288
|
|
|
264
289
|
// Change into s3storage compatible selector
|
|
@@ -267,12 +292,15 @@ const getApp = async (opts = {}) => {
|
|
|
267
292
|
app.use(s3storage.middlewareTransform);
|
|
268
293
|
|
|
269
294
|
app.use(wrapper(version_tag));
|
|
295
|
+
|
|
270
296
|
const csurf = csrf();
|
|
271
297
|
if (!opts.disableCsrf)
|
|
272
298
|
app.use(function (req, res, next) {
|
|
273
299
|
if (
|
|
274
|
-
req.
|
|
275
|
-
|
|
300
|
+
(req.smr &&
|
|
301
|
+
(req.url.startsWith("/api/") ||
|
|
302
|
+
req.url === "/auth/login-with/jwt" ||
|
|
303
|
+
req.url === "/auth/signup")) ||
|
|
276
304
|
jwt_extractor(req)
|
|
277
305
|
)
|
|
278
306
|
return disabledCsurf(req, res, next);
|
|
@@ -280,13 +308,6 @@ const getApp = async (opts = {}) => {
|
|
|
280
308
|
});
|
|
281
309
|
else app.use(disabledCsurf);
|
|
282
310
|
|
|
283
|
-
app.use(function (req, res, next) {
|
|
284
|
-
if (req.headers["x-saltcorn-client"] === "mobile-app") {
|
|
285
|
-
req.smr = true; // saltcorn-mobile-request
|
|
286
|
-
}
|
|
287
|
-
return next();
|
|
288
|
-
});
|
|
289
|
-
|
|
290
311
|
mountRoutes(app);
|
|
291
312
|
// set tenant homepage as / root
|
|
292
313
|
app.get("/", error_catcher(homepage));
|
|
@@ -327,13 +348,13 @@ Sitemap: ${base}sitemap.xml
|
|
|
327
348
|
<urlset
|
|
328
349
|
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
329
350
|
${urls
|
|
330
|
-
|
|
331
|
-
|
|
351
|
+
.map(
|
|
352
|
+
(url) => `<url>
|
|
332
353
|
<loc>${url}</loc>
|
|
333
354
|
<lastmod>${now}</lastmod>
|
|
334
355
|
</url>`
|
|
335
|
-
|
|
336
|
-
|
|
356
|
+
)
|
|
357
|
+
.join("")}
|
|
337
358
|
|
|
338
359
|
</urlset>`);
|
|
339
360
|
})
|
package/auth/admin.js
CHANGED
|
@@ -38,7 +38,9 @@ const {
|
|
|
38
38
|
is_hsts_tld,
|
|
39
39
|
} = require("../markup/admin");
|
|
40
40
|
const { send_verification_email } = require("@saltcorn/data/models/email");
|
|
41
|
-
|
|
41
|
+
const {
|
|
42
|
+
expressionValidator,
|
|
43
|
+
} = require("@saltcorn/data/models/expression");
|
|
42
44
|
/**
|
|
43
45
|
* @type {object}
|
|
44
46
|
* @const
|
|
@@ -177,33 +179,33 @@ const user_dropdown = (user, req, can_reset) =>
|
|
|
177
179
|
req
|
|
178
180
|
),
|
|
179
181
|
can_reset &&
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
182
|
+
post_dropdown_item(
|
|
183
|
+
`/useradmin/reset-password/${user.id}`,
|
|
184
|
+
'<i class="fas fa-envelope"></i> ' +
|
|
185
|
+
req.__("Send password reset email"),
|
|
186
|
+
req
|
|
187
|
+
),
|
|
186
188
|
can_reset &&
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
189
|
+
!user.verified_on &&
|
|
190
|
+
getState().getConfig("verification_view", "") &&
|
|
191
|
+
post_dropdown_item(
|
|
192
|
+
`/useradmin/send-verification/${user.id}`,
|
|
193
|
+
'<i class="fas fa-envelope"></i> ' +
|
|
194
|
+
req.__("Send verification email"),
|
|
195
|
+
req
|
|
196
|
+
),
|
|
195
197
|
user.disabled &&
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
198
|
+
post_dropdown_item(
|
|
199
|
+
`/useradmin/enable/${user.id}`,
|
|
200
|
+
'<i class="fas fa-play"></i> ' + req.__("Enable"),
|
|
201
|
+
req
|
|
202
|
+
),
|
|
201
203
|
!user.disabled &&
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
204
|
+
post_dropdown_item(
|
|
205
|
+
`/useradmin/disable/${user.id}`,
|
|
206
|
+
'<i class="fas fa-pause"></i> ' + req.__("Disable"),
|
|
207
|
+
req
|
|
208
|
+
),
|
|
207
209
|
div({ class: "dropdown-divider" }),
|
|
208
210
|
post_dropdown_item(
|
|
209
211
|
`/useradmin/delete/${user.id}`,
|
|
@@ -257,8 +259,8 @@ router.get(
|
|
|
257
259
|
key: (r) =>
|
|
258
260
|
!!r.verified_on
|
|
259
261
|
? i({
|
|
260
|
-
|
|
261
|
-
|
|
262
|
+
class: "fas fa-check-circle text-success",
|
|
263
|
+
})
|
|
262
264
|
: "",
|
|
263
265
|
},
|
|
264
266
|
{ label: req.__("Role"), key: (r) => roleMap[r.role_id] },
|
|
@@ -421,15 +423,15 @@ router.get(
|
|
|
421
423
|
above: [
|
|
422
424
|
...(letsencrypt && has_custom
|
|
423
425
|
? [
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
426
|
+
{
|
|
427
|
+
type: "card",
|
|
428
|
+
contents: p(
|
|
429
|
+
req.__(
|
|
430
|
+
"You have enabled both Let's Encrypt certificates and custom SSL certificates. Let's Encrypt takes priority and the custom certificates will be ignored."
|
|
431
|
+
)
|
|
432
|
+
),
|
|
433
|
+
},
|
|
434
|
+
]
|
|
433
435
|
: []),
|
|
434
436
|
{
|
|
435
437
|
type: "card",
|
|
@@ -450,33 +452,33 @@ router.get(
|
|
|
450
452
|
),
|
|
451
453
|
letsencrypt
|
|
452
454
|
? post_btn(
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
455
|
+
"/config/delete/letsencrypt",
|
|
456
|
+
req.__("Disable LetsEncrypt HTTPS"),
|
|
457
|
+
req.csrfToken(),
|
|
458
|
+
{ btnClass: "btn-danger", req }
|
|
459
|
+
)
|
|
458
460
|
: post_btn(
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
461
|
+
"/admin/enable-letsencrypt",
|
|
462
|
+
req.__("Enable LetsEncrypt HTTPS"),
|
|
463
|
+
req.csrfToken(),
|
|
464
|
+
{ confirm: true, req }
|
|
465
|
+
),
|
|
464
466
|
!letsencrypt &&
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
)
|
|
473
|
-
),
|
|
474
|
-
p(
|
|
475
|
-
req.__(
|
|
476
|
-
"The DNS A records (for * and @, or a subdomain) should point to this server's IP address before enabling LetsEncrypt"
|
|
477
|
-
)
|
|
467
|
+
show_warning &&
|
|
468
|
+
!has_custom &&
|
|
469
|
+
div(
|
|
470
|
+
{ class: "mt-3 alert alert-danger" },
|
|
471
|
+
p(
|
|
472
|
+
req.__(
|
|
473
|
+
"The address you are using to reach Saltcorn does not match the Base URL."
|
|
478
474
|
)
|
|
479
475
|
),
|
|
476
|
+
p(
|
|
477
|
+
req.__(
|
|
478
|
+
"The DNS A records (for * and @, or a subdomain) should point to this server's IP address before enabling LetsEncrypt"
|
|
479
|
+
)
|
|
480
|
+
)
|
|
481
|
+
),
|
|
480
482
|
],
|
|
481
483
|
},
|
|
482
484
|
{
|
|
@@ -570,8 +572,8 @@ router.post(
|
|
|
570
572
|
req.flash(
|
|
571
573
|
"success",
|
|
572
574
|
req.__("Custom SSL enabled. Restart for changes to take effect.") +
|
|
573
|
-
|
|
574
|
-
|
|
575
|
+
" " +
|
|
576
|
+
a({ href: "/admin/system" }, req.__("Restart here"))
|
|
575
577
|
);
|
|
576
578
|
if (!req.xhr) {
|
|
577
579
|
res.redirect("/useradmin/ssl");
|
|
@@ -580,6 +582,103 @@ router.post(
|
|
|
580
582
|
})
|
|
581
583
|
);
|
|
582
584
|
|
|
585
|
+
/**
|
|
586
|
+
* @name get/ssl/custom
|
|
587
|
+
* @function
|
|
588
|
+
* @memberof module:auth/admin~auth/adminRouter
|
|
589
|
+
*/
|
|
590
|
+
router.get(
|
|
591
|
+
"/table-access",
|
|
592
|
+
isAdmin,
|
|
593
|
+
error_catcher(async (req, res) => {
|
|
594
|
+
const tables = await Table.find()
|
|
595
|
+
const roleOptions = (await User.get_roles()).map((r) => ({
|
|
596
|
+
value: r.id,
|
|
597
|
+
label: r.role,
|
|
598
|
+
}));
|
|
599
|
+
|
|
600
|
+
const contents = []
|
|
601
|
+
for (const table of tables) {
|
|
602
|
+
if (table.external) continue
|
|
603
|
+
const fields = await table.getFields();
|
|
604
|
+
const userFields = fields
|
|
605
|
+
.filter((f) => f.reftable_name === "users")
|
|
606
|
+
.map((f) => ({ value: f.id, label: f.name }));
|
|
607
|
+
const form = new Form({
|
|
608
|
+
action: "/table",
|
|
609
|
+
noSubmitButton: true,
|
|
610
|
+
onChange: "saveAndContinue(this)",
|
|
611
|
+
fields: [
|
|
612
|
+
{
|
|
613
|
+
label: req.__("Ownership field"),
|
|
614
|
+
name: "ownership_field_id",
|
|
615
|
+
sublabel: req.__(
|
|
616
|
+
"The user referred to in this field will be the owner of the row"
|
|
617
|
+
),
|
|
618
|
+
input_type: "select",
|
|
619
|
+
options: [
|
|
620
|
+
{ value: "", label: req.__("None") },
|
|
621
|
+
...userFields,
|
|
622
|
+
{ value: "_formula", label: req.__("Formula") },
|
|
623
|
+
],
|
|
624
|
+
},
|
|
625
|
+
{
|
|
626
|
+
name: "ownership_formula",
|
|
627
|
+
label: req.__("Ownership formula"),
|
|
628
|
+
validator: expressionValidator,
|
|
629
|
+
type: "String",
|
|
630
|
+
class: "validate-expression",
|
|
631
|
+
sublabel:
|
|
632
|
+
req.__("User is treated as owner if true. In scope: ") +
|
|
633
|
+
["user", ...fields.map((f) => f.name)]
|
|
634
|
+
.map((fn) => code(fn))
|
|
635
|
+
.join(", "),
|
|
636
|
+
showIf: { ownership_field_id: "_formula" },
|
|
637
|
+
},
|
|
638
|
+
{
|
|
639
|
+
label: req.__("Minimum role to read"),
|
|
640
|
+
sublabel: req.__(
|
|
641
|
+
"User must have this role or higher to read rows from the table, unless they are the owner"
|
|
642
|
+
),
|
|
643
|
+
name: "min_role_read",
|
|
644
|
+
input_type: "select",
|
|
645
|
+
options: roleOptions,
|
|
646
|
+
attributes: { asideNext: true }
|
|
647
|
+
},
|
|
648
|
+
{
|
|
649
|
+
label: req.__("Minimum role to write"),
|
|
650
|
+
name: "min_role_write",
|
|
651
|
+
input_type: "select",
|
|
652
|
+
sublabel: req.__(
|
|
653
|
+
"User must have this role or higher to edit or create new rows in the table, unless they are the owner"
|
|
654
|
+
),
|
|
655
|
+
options: roleOptions,
|
|
656
|
+
},
|
|
657
|
+
]
|
|
658
|
+
})
|
|
659
|
+
form.hidden("id", "name");
|
|
660
|
+
form.values = table
|
|
661
|
+
if (table.ownership_formula && !table.ownership_field_id)
|
|
662
|
+
form.values.ownership_field_id = "_formula";
|
|
663
|
+
contents.push(div(
|
|
664
|
+
h5(a({ href: `/table/${table.id}` }, table.name)),
|
|
665
|
+
renderForm(form, req.csrfToken())
|
|
666
|
+
))
|
|
667
|
+
}
|
|
668
|
+
send_users_page({
|
|
669
|
+
res,
|
|
670
|
+
req,
|
|
671
|
+
active_sub: "Table access",
|
|
672
|
+
contents: {
|
|
673
|
+
type: "card",
|
|
674
|
+
title: req.__("Table access"),
|
|
675
|
+
contents
|
|
676
|
+
},
|
|
677
|
+
});
|
|
678
|
+
})
|
|
679
|
+
);
|
|
680
|
+
|
|
681
|
+
|
|
583
682
|
/**
|
|
584
683
|
* @name get/:id
|
|
585
684
|
* @function
|
|
@@ -613,9 +712,9 @@ router.get(
|
|
|
613
712
|
div(
|
|
614
713
|
user.api_token
|
|
615
714
|
? span(
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
715
|
+
{ class: "me-1" },
|
|
716
|
+
req.__("API token for this user: ")
|
|
717
|
+
) + code(user.api_token)
|
|
619
718
|
: req.__("No API token issued")
|
|
620
719
|
),
|
|
621
720
|
// button for reset or generate api token
|
|
@@ -629,16 +728,16 @@ router.get(
|
|
|
629
728
|
),
|
|
630
729
|
// button for remove api token
|
|
631
730
|
user.api_token &&
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
731
|
+
div(
|
|
732
|
+
{ class: "mt-4 ms-2 d-inline-block" },
|
|
733
|
+
post_btn(
|
|
734
|
+
`/useradmin/remove-api-token/${user.id}`,
|
|
735
|
+
// TBD localization
|
|
736
|
+
user.api_token ? req.__("Remove") : req.__("Generate"),
|
|
737
|
+
req.csrfToken(),
|
|
738
|
+
{ req: req, confirm: true }
|
|
739
|
+
)
|
|
740
|
+
),
|
|
642
741
|
],
|
|
643
742
|
},
|
|
644
743
|
],
|
package/auth/routes.js
CHANGED
|
@@ -199,33 +199,66 @@ const getAuthLinks = (current, noMethods) => {
|
|
|
199
199
|
return links;
|
|
200
200
|
};
|
|
201
201
|
|
|
202
|
-
const loginWithJwt = async (email, password, res) => {
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
const now = new Date();
|
|
202
|
+
const loginWithJwt = async (email, password, saltcornApp, res) => {
|
|
203
|
+
const loginFn = async () => {
|
|
204
|
+
const publicUserLink = getState().getConfig("public_user_link");
|
|
206
205
|
const jwt_secret = db.connectObj.jwt_secret;
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
206
|
+
if (email && password) {
|
|
207
|
+
// with credentials
|
|
208
|
+
const user = await User.findOne({ email });
|
|
209
|
+
if (user && user.checkPassword(password)) {
|
|
210
|
+
const now = new Date();
|
|
211
|
+
const token = jwt.sign(
|
|
212
|
+
{
|
|
213
|
+
sub: email,
|
|
214
|
+
user: {
|
|
215
|
+
id: user.id,
|
|
216
|
+
email: user.email,
|
|
217
|
+
role_id: user.role_id,
|
|
218
|
+
language: user.language ? user.language : "en",
|
|
219
|
+
disabled: user.disabled,
|
|
220
|
+
},
|
|
221
|
+
iss: "saltcorn@saltcorn",
|
|
222
|
+
aud: "saltcorn-mobile-app",
|
|
223
|
+
iat: now.valueOf(),
|
|
224
|
+
tenant: db.getTenantSchema(),
|
|
225
|
+
},
|
|
226
|
+
jwt_secret
|
|
227
|
+
);
|
|
228
|
+
if (!user.last_mobile_login) await user.updateLastMobileLogin(now);
|
|
229
|
+
res.json(token);
|
|
230
|
+
} else {
|
|
231
|
+
res.json({
|
|
232
|
+
alerts: [{ type: "danger", msg: "Incorrect user or password" }],
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
} else if (publicUserLink) {
|
|
236
|
+
// public login
|
|
237
|
+
const token = jwt.sign(
|
|
238
|
+
{
|
|
239
|
+
sub: "public",
|
|
240
|
+
user: {
|
|
241
|
+
role_id: 10,
|
|
242
|
+
language: "en",
|
|
243
|
+
},
|
|
244
|
+
iss: "saltcorn@saltcorn",
|
|
245
|
+
aud: "saltcorn-mobile-app",
|
|
246
|
+
iat: new Date().valueOf(),
|
|
247
|
+
tenant: db.getTenantSchema(),
|
|
216
248
|
},
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
249
|
+
jwt_secret
|
|
250
|
+
);
|
|
251
|
+
res.json(token);
|
|
252
|
+
} else {
|
|
253
|
+
res.json({
|
|
254
|
+
alerts: [{ type: "danger", msg: "The public login is deactivated" }],
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
if (saltcornApp && saltcornApp !== db.connectObj.default_schema) {
|
|
259
|
+
await db.runWithTenant(saltcornApp, loginFn);
|
|
225
260
|
} else {
|
|
226
|
-
|
|
227
|
-
alerts: [{ type: "danger", msg: "Incorrect user or password" }],
|
|
228
|
-
});
|
|
261
|
+
await loginFn();
|
|
229
262
|
}
|
|
230
263
|
};
|
|
231
264
|
|
|
@@ -899,7 +932,13 @@ router.post(
|
|
|
899
932
|
} else {
|
|
900
933
|
const u = await User.create({ email, password });
|
|
901
934
|
await send_verification_email(u, req);
|
|
902
|
-
if (req.smr)
|
|
935
|
+
if (req.smr)
|
|
936
|
+
await loginWithJwt(
|
|
937
|
+
email,
|
|
938
|
+
password,
|
|
939
|
+
req.headers["x-saltcorn-app"],
|
|
940
|
+
res
|
|
941
|
+
);
|
|
903
942
|
else signup_login_with_user(u, req, res);
|
|
904
943
|
}
|
|
905
944
|
}
|
|
@@ -1008,7 +1047,7 @@ router.get(
|
|
|
1008
1047
|
const { method } = req.params;
|
|
1009
1048
|
if (method === "jwt") {
|
|
1010
1049
|
const { email, password } = req.query;
|
|
1011
|
-
await loginWithJwt(email, password, res);
|
|
1050
|
+
await loginWithJwt(email, password, req.headers["x-saltcorn-app"], res);
|
|
1012
1051
|
} else {
|
|
1013
1052
|
const auth = getState().auth_methods[method];
|
|
1014
1053
|
if (auth) {
|
|
@@ -1144,7 +1183,7 @@ const setLanguageForm = (req, user) =>
|
|
|
1144
1183
|
option(
|
|
1145
1184
|
{
|
|
1146
1185
|
value: locale,
|
|
1147
|
-
...(user && user.language === locale && { selected: true }),
|
|
1186
|
+
...(((user && user.language === locale) || (user && !user.language && req.getLocale() === locale)) && { selected: true }),
|
|
1148
1187
|
},
|
|
1149
1188
|
language
|
|
1150
1189
|
)
|
|
@@ -1368,7 +1407,7 @@ router.get(
|
|
|
1368
1407
|
return;
|
|
1369
1408
|
}
|
|
1370
1409
|
res.sendWrap(
|
|
1371
|
-
req.__("User settings"),
|
|
1410
|
+
req.__("User settings") || "User settings",
|
|
1372
1411
|
await userSettings({ req, res, pwform: changPwForm(req), user })
|
|
1373
1412
|
);
|
|
1374
1413
|
})
|
package/locales/en.json
CHANGED
|
@@ -983,5 +983,57 @@
|
|
|
983
983
|
"Restore/download automated backups »": "Restore/download automated backups »",
|
|
984
984
|
"Snapshots store your application structure and definition, without the table data. Individual views and pages can be restored from snapshots from the <a href='/viewedit'>view</a> or <a href='/pageedit'>pages</a> overviews (\"Restore\" from individual page or view dropdowns).": "Snapshots store your application structure and definition, without the table data. Individual views and pages can be restored from snapshots from the <a href='/viewedit'>view</a> or <a href='/pageedit'>pages</a> overviews (\"Restore\" from individual page or view dropdowns).",
|
|
985
985
|
"List/download snapshots »": "List/download snapshots »",
|
|
986
|
-
"Discover tables that are already in the Database, but not known to Saltcorn": "Discover tables that are already in the Database, but not known to Saltcorn"
|
|
987
|
-
|
|
986
|
+
"Discover tables that are already in the Database, but not known to Saltcorn": "Discover tables that are already in the Database, but not known to Saltcorn",
|
|
987
|
+
"Split paste": "Split paste",
|
|
988
|
+
"Separate paste content into separate inputs": "Separate paste content into separate inputs",
|
|
989
|
+
"Add entries to tag": "Add entries to tag",
|
|
990
|
+
"Add pages": "Add pages",
|
|
991
|
+
"Add triggers": "Add triggers",
|
|
992
|
+
"Formula value": "Formula value",
|
|
993
|
+
"The build was successfully": "The build was successfully",
|
|
994
|
+
"Unable to build the app": "Unable to build the app",
|
|
995
|
+
"Add tag": "Add tag",
|
|
996
|
+
"Create new row": "Create new row",
|
|
997
|
+
"Specify how to create a new row": "Specify how to create a new row",
|
|
998
|
+
"Preview": "Preview",
|
|
999
|
+
"Minimum role updated": "Minimum role updated",
|
|
1000
|
+
"Module not found": "Module not found",
|
|
1001
|
+
"View %s not found": "View %s not found",
|
|
1002
|
+
"Query %s not found": "Query %s not found",
|
|
1003
|
+
"Open": "Open",
|
|
1004
|
+
"Only the android build supports docker.": "Only the android build supports docker.",
|
|
1005
|
+
"Please enter a valid server URL.": "Please enter a valid server URL.",
|
|
1006
|
+
"Table access": "Table access",
|
|
1007
|
+
"Download one of the backups above": "Download one of the backups above",
|
|
1008
|
+
"Clear this application": "Clear this application",
|
|
1009
|
+
"(tick all boxes)": "(tick all boxes)",
|
|
1010
|
+
"When prompted to create the first user, click the link to restore a backup": "When prompted to create the first user, click the link to restore a backup",
|
|
1011
|
+
"Select the downloaded backup file": "Select the downloaded backup file",
|
|
1012
|
+
"Units": "Units",
|
|
1013
|
+
"Descending?": "Descending?",
|
|
1014
|
+
"Small": "Small",
|
|
1015
|
+
"Medium": "Medium",
|
|
1016
|
+
"Large": "Large",
|
|
1017
|
+
"Extra-large": "Extra-large",
|
|
1018
|
+
"Please select at least one item": "Please select at least one item",
|
|
1019
|
+
"Only include rows where this formula is true. ": "Only include rows where this formula is true. ",
|
|
1020
|
+
"Use %s to access current user ID": "Use %s to access current user ID",
|
|
1021
|
+
"Action not found": "Action not found",
|
|
1022
|
+
"Development settings": "Development settings",
|
|
1023
|
+
"All entities": "All entities",
|
|
1024
|
+
"no tags": "no tags",
|
|
1025
|
+
"Development mode settings updated": "Development mode settings updated",
|
|
1026
|
+
"Locale identifier short code, e.g. en, zh, fr, ar etc. ": "Locale identifier short code, e.g. en, zh, fr, ar etc. ",
|
|
1027
|
+
"Is this the default language in which the application is built?": "Is this the default language in which the application is built?",
|
|
1028
|
+
"Database type": "Database type",
|
|
1029
|
+
"Database schema name": "Database schema name",
|
|
1030
|
+
"Database user": "Database user",
|
|
1031
|
+
"Database host": "Database host",
|
|
1032
|
+
"Database port": "Database port",
|
|
1033
|
+
"Creator email": "Creator email",
|
|
1034
|
+
"Create tenant warning text": "Create tenant warning text",
|
|
1035
|
+
"Provide your own create warning text if need": "Provide your own create warning text if need",
|
|
1036
|
+
"Specify some description for tenant if need": "Specify some description for tenant if need",
|
|
1037
|
+
"Created": "Created",
|
|
1038
|
+
"First user E-mail": "First user E-mail"
|
|
1039
|
+
}
|