@saltcorn/server 0.9.5-beta.9 → 0.9.5
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 +1 -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/auth/routes.js
CHANGED
|
@@ -45,6 +45,7 @@ const {
|
|
|
45
45
|
p,
|
|
46
46
|
script,
|
|
47
47
|
domReady,
|
|
48
|
+
button,
|
|
48
49
|
} = require("@saltcorn/markup/tags");
|
|
49
50
|
const {
|
|
50
51
|
available_languages,
|
|
@@ -237,13 +238,7 @@ const loginWithJwt = async (email, password, saltcornApp, res, req) => {
|
|
|
237
238
|
const token = jwt.sign(
|
|
238
239
|
{
|
|
239
240
|
sub: email,
|
|
240
|
-
user:
|
|
241
|
-
id: user.id,
|
|
242
|
-
email: user.email,
|
|
243
|
-
role_id: user.role_id,
|
|
244
|
-
language: user.language ? user.language : "en",
|
|
245
|
-
disabled: user.disabled,
|
|
246
|
-
},
|
|
241
|
+
user: user.session_object,
|
|
247
242
|
iss: "saltcorn@saltcorn",
|
|
248
243
|
aud: "saltcorn-mobile-app",
|
|
249
244
|
iat: now.valueOf(),
|
|
@@ -1362,6 +1357,57 @@ const userSettings = async ({ req, res, pwform, user }) => {
|
|
|
1362
1357
|
),
|
|
1363
1358
|
],
|
|
1364
1359
|
};
|
|
1360
|
+
let themeCfgCard;
|
|
1361
|
+
const layoutPlugin = getState().getLayoutPlugin(user);
|
|
1362
|
+
const modNames = getState().plugin_module_names;
|
|
1363
|
+
const pluginName = layoutPlugin.plugin_name;
|
|
1364
|
+
let safeName = pluginName;
|
|
1365
|
+
for (const [k, v] of Object.entries(modNames)) {
|
|
1366
|
+
if (v === pluginName) safeName = k;
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
const hasUserConfigs =
|
|
1370
|
+
layoutPlugin.user_config_form &&
|
|
1371
|
+
(await layoutPlugin.user_config_form(
|
|
1372
|
+
getState().plugin_cfgs[pluginName] || {}
|
|
1373
|
+
)) !== null;
|
|
1374
|
+
themeCfgCard = {
|
|
1375
|
+
type: "card",
|
|
1376
|
+
title: req.__("Layout"),
|
|
1377
|
+
contents: [
|
|
1378
|
+
div(
|
|
1379
|
+
hasUserConfigs
|
|
1380
|
+
? req.__("Adjust the the theme for this user")
|
|
1381
|
+
: req.__("The current theme has no user specific settings")
|
|
1382
|
+
),
|
|
1383
|
+
hasUserConfigs
|
|
1384
|
+
? div(
|
|
1385
|
+
{
|
|
1386
|
+
class: "mt-4",
|
|
1387
|
+
},
|
|
1388
|
+
|
|
1389
|
+
a(
|
|
1390
|
+
{
|
|
1391
|
+
class: "btn btn-primary",
|
|
1392
|
+
role: "button",
|
|
1393
|
+
href: `/plugins/user_configure/${encodeURIComponent(safeName)}`,
|
|
1394
|
+
title: req.__("Configure theme"),
|
|
1395
|
+
},
|
|
1396
|
+
req.__("Configure")
|
|
1397
|
+
),
|
|
1398
|
+
button(
|
|
1399
|
+
{
|
|
1400
|
+
class: "btn btn-primary ms-2",
|
|
1401
|
+
onclick: "ajax_post('/plugins/remove_user_layout')",
|
|
1402
|
+
title: req.__("Remove all user specific theme settings"),
|
|
1403
|
+
},
|
|
1404
|
+
req.__("Reset")
|
|
1405
|
+
)
|
|
1406
|
+
)
|
|
1407
|
+
: "",
|
|
1408
|
+
],
|
|
1409
|
+
};
|
|
1410
|
+
|
|
1365
1411
|
return {
|
|
1366
1412
|
above: [
|
|
1367
1413
|
{
|
|
@@ -1434,6 +1480,7 @@ const userSettings = async ({ req, res, pwform, user }) => {
|
|
|
1434
1480
|
]
|
|
1435
1481
|
: []),
|
|
1436
1482
|
...(apikeycard ? [apikeycard] : []),
|
|
1483
|
+
...(themeCfgCard ? [themeCfgCard] : []),
|
|
1437
1484
|
],
|
|
1438
1485
|
};
|
|
1439
1486
|
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
To build an Android app for the Play Store, you need to create an Android Application Bundle (.aab file) and sign the app with a certificate. A keystore file, a keystore alias, and a keystore password are needed for this.
|
|
2
|
+
|
|
3
|
+
*Note: The builder creates .aab files for the release Build type and .apk files for debug.*
|
|
4
|
+
|
|
5
|
+
- **Keystore file:** A self-signed certificate that includes the private key used to sign your app. When you upload the app, you must sign it. However, before you publish it, you can use another key controlled by the Google Play App Signing feature.
|
|
6
|
+
- **Keystore alias:** A unique name to identify the key within the keystore file.
|
|
7
|
+
- **Keystore password:** The password to access the keystore file.
|
|
8
|
+
|
|
9
|
+
*Note: You need a [Play Console developer account](https://support.google.com/googleplay/android-developer/answer/6112435?hl=en&ref_topic=3450769&sjid=11090022771305927482-EU) to publish your app on the Play Store.*
|
|
10
|
+
|
|
11
|
+
### Create a Keysore file
|
|
12
|
+
On any Unix-based system, you can use the `keytool` command to create the keystore file. For example:
|
|
13
|
+
```sh
|
|
14
|
+
keytool -genkey -v -keystore my-app-key.jks
|
|
15
|
+
-keyalg RSA -keysize 2048 -validity 3650
|
|
16
|
+
-alias my-key-alias
|
|
17
|
+
-storepass mypassword
|
|
18
|
+
```
|
|
19
|
+
genereates a keystore file named **keystore my-app-key.jks** with the alias **my-key-alias** and with **mypassword** as password.
|
|
20
|
+
|
|
21
|
+
You will be prompted for additional information. Once this is done, upload **my-app-key.jks** into the keystore_files directory of your Saltcorn installation, and it shows up.
|
|
22
|
+
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
To build and publish your iOS app, you need to set up a Provisioning Profile.
|
|
2
|
+
Follow these steps to configure it correctly and optionally upload it to the App Store.
|
|
3
|
+
|
|
4
|
+
*Note: You need an enrolled [Apple Developer Account](https://developer.apple.com/programs/).*
|
|
5
|
+
|
|
6
|
+
## Apple Developer Account
|
|
7
|
+
In your Apple Developer Account create an App ID, a Certificate, and a Provisioning Profile.
|
|
8
|
+
|
|
9
|
+
- **App ID:** Identifies your app in provisioning profiles. Use the ID from this builder dialog.
|
|
10
|
+
- **Certificate:** Used to sign your app, verifying the creator and ensuring the source hasn't been altered.
|
|
11
|
+
- **Provisioning Profile:** Combines the App ID and Certificate, along with other configurations, to build iOS apps.
|
|
12
|
+
|
|
13
|
+
## App Store Connect
|
|
14
|
+
To publish your app, you must create a new app in your App Store Connect account and upload the IPA file from this build.
|
|
15
|
+
## Step-by-Step Instructions
|
|
16
|
+
|
|
17
|
+
### 1. Register App ID
|
|
18
|
+
1. Navigate to the [Identifiers](https://developer.apple.com/account/resources/identifiers/list) section.
|
|
19
|
+
2. Click the plus button and select 'App IDs' followed by 'App' in the subsequent dialog.
|
|
20
|
+
3. Enter a description and the actual App ID (same as in the builder dialog).
|
|
21
|
+
4. Click **Continue**, review your entries, and finish by clicking **Register**.
|
|
22
|
+
|
|
23
|
+
### 2. Create Certificate
|
|
24
|
+
1. Go to the [Certificates](https://developer.apple.com/account/resources/certificates/list) section and click the plus button.
|
|
25
|
+
2. Select 'Apple Distribution'.
|
|
26
|
+
3. Generate and upload a Certificate Signing Request from your local machine.
|
|
27
|
+
|
|
28
|
+
##### 2.1 Certificate Signing Request
|
|
29
|
+
1. Open the Keychain Access tool via Launchpad.
|
|
30
|
+
2. Navigate to **Keychain Access > Certificate Assistant** and select **Request a Certificate from a Certificate Authority**.
|
|
31
|
+
3. Fill out 'User Email Address' and 'Common Name', leaving 'CA Email Address' empty, and select 'Saved to disk'.
|
|
32
|
+
4. Save the file and upload it through your browser.
|
|
33
|
+
5. Click **Continue**, download the generated Certificate, and double-click the file to install it locally.
|
|
34
|
+
|
|
35
|
+
After that, the Certificate and its private key are installed locally.
|
|
36
|
+
|
|
37
|
+
##### 2.2 Permit Access to the Certificate
|
|
38
|
+
You have to permit using the Certificate's private key; otherwise, the build blocks with a confirm dialog on your local Mac.
|
|
39
|
+
1. Open Keychain Access and select the login default keychain (left corner of the window).
|
|
40
|
+
2. Locate your certificate, it will look something like
|
|
41
|
+
```Apple Distribution: [your name] ([Team ID])```
|
|
42
|
+
3. Expand it to view the private key, then double-click to open its properties.
|
|
43
|
+
4. Go to the **Access Control** tab and activate 'Allow all applications to access this item'.
|
|
44
|
+
|
|
45
|
+
**Note:** You can also select 'Always allow' when the confirmation dialog appears on your local Mac.
|
|
46
|
+
|
|
47
|
+
### 3. Create a Provisioning Profile
|
|
48
|
+
1. Go to the [Profiles](https://developer.apple.com/account/resources/profiles/list) section and click the plus button.
|
|
49
|
+
2. Choose 'App Store Connect'.
|
|
50
|
+
3. In the following steps, use the App ID and Certificate you created.
|
|
51
|
+
4. Choose any name for the profile, click **Generate**, and download the file.
|
|
52
|
+
5. Double-click the downloaded file to install the Provisioning Profile on your local Mac.
|
|
53
|
+
|
|
54
|
+
Finally, upload the Provisioning Profile into the 'provisioning_files' directory of your Saltcorn installation, so you can select it here.
|
|
55
|
+
### 4 Upload to App Store Connect
|
|
56
|
+
When you run a build with a valid provisioning profile, the builder generates an .ipa file.
|
|
57
|
+
You can download this file and upload it to [App Store Connect](https://appstoreconnect.apple.com/apps)
|
|
58
|
+
using the Transporter tool on your Mac.
|
|
59
|
+
|
|
60
|
+
**Note:** Ensure that your App Store Connect account has an app that matches your App ID before uploading the file.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
xcodebuild
|
package/load_plugins.js
CHANGED
|
@@ -35,6 +35,10 @@ const loadPlugin = async (plugin, force) => {
|
|
|
35
35
|
res.name
|
|
36
36
|
);
|
|
37
37
|
} catch (error) {
|
|
38
|
+
getState().log(
|
|
39
|
+
3,
|
|
40
|
+
`Error loading plugin ${plugin.name}: ${error.message || error}`
|
|
41
|
+
);
|
|
38
42
|
if (force) {
|
|
39
43
|
// remove the install dir and try again
|
|
40
44
|
await loader.remove();
|
|
@@ -48,6 +52,7 @@ const loadPlugin = async (plugin, force) => {
|
|
|
48
52
|
);
|
|
49
53
|
}
|
|
50
54
|
}
|
|
55
|
+
if (res.plugin_module.user_config_form) getState().refreshUserLayouts();
|
|
51
56
|
if (res.plugin_module.onLoad) {
|
|
52
57
|
try {
|
|
53
58
|
await res.plugin_module.onLoad(plugin.configuration);
|
|
@@ -83,6 +88,7 @@ const loadAllPlugins = async (force) => {
|
|
|
83
88
|
console.error(e);
|
|
84
89
|
}
|
|
85
90
|
}
|
|
91
|
+
await getState().refreshUserLayouts();
|
|
86
92
|
await getState().refresh(true);
|
|
87
93
|
};
|
|
88
94
|
|
package/locales/en.json
CHANGED
|
@@ -1391,5 +1391,30 @@
|
|
|
1391
1391
|
"refresh": "refresh",
|
|
1392
1392
|
"installed": "installed",
|
|
1393
1393
|
"Include table history in backup": "Include table history in backup",
|
|
1394
|
-
"The plugin was corrupted and had to be repaired. We recommend restarting your server.": "The plugin was corrupted and had to be repaired. We recommend restarting your server."
|
|
1395
|
-
|
|
1394
|
+
"The plugin was corrupted and had to be repaired. We recommend restarting your server.": "The plugin was corrupted and had to be repaired. We recommend restarting your server.",
|
|
1395
|
+
"%s code page": "%s code page",
|
|
1396
|
+
"Constants and function code": "Constants and function code",
|
|
1397
|
+
"Delete code page": "Delete code page",
|
|
1398
|
+
"Adjust the the theme for this user": "Adjust the the theme for this user",
|
|
1399
|
+
"Configure theme": "Configure theme",
|
|
1400
|
+
"Remove all user specific theme settings": "Remove all user specific theme settings",
|
|
1401
|
+
"Configure %s Plugin for %s": "Configure %s Plugin for %s",
|
|
1402
|
+
"The current theme has no user specific settings": "The current theme has no user specific settings",
|
|
1403
|
+
"Some themes support only one level of menu nesting.": "Some themes support only one level of menu nesting.",
|
|
1404
|
+
"Apple Team ID": "Apple Team ID",
|
|
1405
|
+
"Please enter your Apple Team ID": "Please enter your Apple Team ID",
|
|
1406
|
+
"To see changes for '%s' in show-if-formulas, users need to relogin": "To see changes for '%s' in show-if-formulas, users need to relogin",
|
|
1407
|
+
"Server host": "Server host",
|
|
1408
|
+
"Username": "Username",
|
|
1409
|
+
"Port": "Port",
|
|
1410
|
+
"All tenants": "All tenants",
|
|
1411
|
+
"Also backup all tenants": "Also backup all tenants",
|
|
1412
|
+
"Retain local directory": "Retain local directory",
|
|
1413
|
+
"Retain a local backup copy in this directory (optional)": "Retain a local backup copy in this directory (optional)",
|
|
1414
|
+
"Do not wrap response in a success object": "Do not wrap response in a success object",
|
|
1415
|
+
"Use table description instead of name as header": "Use table description instead of name as header",
|
|
1416
|
+
"Description header": "Description header",
|
|
1417
|
+
"Lazy load views": "Lazy load views",
|
|
1418
|
+
"Log IP address": "Log IP address",
|
|
1419
|
+
"Record the request IP address in log messages": "Record the request IP address in log messages"
|
|
1420
|
+
}
|