@saltcorn/mobile-app 0.7.4 → 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/config.xml +2 -0
- package/package.json +4 -10
- package/www/index.html +27 -10
- package/www/js/mocks/request.js +2 -1
- package/www/js/routes/auth.js +2 -1
- package/www/js/routes/page.js +5 -5
- package/www/js/routes/view.js +3 -3
- package/www/js/utils/global_utils.js +10 -18
- package/www/js/utils/iframe_view_utils.js +72 -35
- package/www/js/utils/table_utils.js +28 -4
package/config.xml
CHANGED
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saltcorn/mobile-app",
|
|
3
3
|
"displayName": "Saltcorn mobile app",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.8.0-beta.0",
|
|
5
5
|
"description": "Apache Cordova application with @saltcorn/markup",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"add-platform": "cordova platform add",
|
|
9
|
+
"add-plugin": "cordova plugin add",
|
|
9
10
|
"build-app": "cordova build "
|
|
10
11
|
},
|
|
11
12
|
"author": "Christian Hugo",
|
|
@@ -13,12 +14,7 @@
|
|
|
13
14
|
"cordova": {
|
|
14
15
|
"platforms": [
|
|
15
16
|
"android"
|
|
16
|
-
]
|
|
17
|
-
"plugins": {
|
|
18
|
-
"cordova-sqlite-ext": {},
|
|
19
|
-
"cordova-plugin-file": {},
|
|
20
|
-
"cordova-plugin-inappbrowser": {}
|
|
21
|
-
}
|
|
17
|
+
]
|
|
22
18
|
},
|
|
23
19
|
"overrides": {
|
|
24
20
|
"ansi-regex": "4.1.1"
|
|
@@ -28,8 +24,6 @@
|
|
|
28
24
|
"cordova-sqlite-ext": "^6.0.0"
|
|
29
25
|
},
|
|
30
26
|
"devDependencies": {
|
|
31
|
-
"cordova-android": "^10.1.2"
|
|
32
|
-
"cordova-plugin-file": "^6.0.2",
|
|
33
|
-
"cordova-plugin-inappbrowser": "^5.0.0"
|
|
27
|
+
"cordova-android": "^10.1.2"
|
|
34
28
|
}
|
|
35
29
|
}
|
package/www/index.html
CHANGED
|
@@ -143,14 +143,30 @@
|
|
|
143
143
|
iframe.contentWindow._sc_version_tag = config.version_tag;
|
|
144
144
|
};
|
|
145
145
|
|
|
146
|
+
const initJwt = async () => {
|
|
147
|
+
if (!(await saltcorn.data.db.tableExists("jwt_table"))) {
|
|
148
|
+
await createJwtTable();
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
const jwt = await getJwt();
|
|
152
|
+
if(jwt) {
|
|
153
|
+
const state = saltcorn.data.state.getState();
|
|
154
|
+
state.mobileConfig.jwt = jwt;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
146
159
|
const checkJWT = async () => {
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
160
|
+
const state = saltcorn.data.state.getState();
|
|
161
|
+
const jwt = state.mobileConfig.jwt;
|
|
162
|
+
if(jwt && jwt !== "undefined") {
|
|
163
|
+
const response = await apiCall({
|
|
164
|
+
method: "GET",
|
|
165
|
+
path: "/auth/authenticated",
|
|
166
|
+
});
|
|
167
|
+
return response.data.authenticated;
|
|
168
|
+
}
|
|
169
|
+
else return false;
|
|
154
170
|
};
|
|
155
171
|
|
|
156
172
|
const initI18Next = async () => {
|
|
@@ -199,6 +215,7 @@
|
|
|
199
215
|
if (updateNeeded) {
|
|
200
216
|
await updateDb(tablesJSON);
|
|
201
217
|
}
|
|
218
|
+
await initJwt();
|
|
202
219
|
await state.refresh_tables();
|
|
203
220
|
await state.refresh_views();
|
|
204
221
|
await state.refresh_pages();
|
|
@@ -212,8 +229,8 @@
|
|
|
212
229
|
await initI18Next();
|
|
213
230
|
try {
|
|
214
231
|
if (await checkJWT()) {
|
|
215
|
-
const decodedJwt = jwt_decode(localStorage.getItem("auth_jwt"));
|
|
216
232
|
const mobileConfig = state.mobileConfig;
|
|
233
|
+
const decodedJwt = jwt_decode(mobileConfig.jwt);
|
|
217
234
|
mobileConfig.role_id = decodedJwt.user.role_id
|
|
218
235
|
? decodedJwt.user.role_id
|
|
219
236
|
: 10;
|
|
@@ -226,7 +243,7 @@
|
|
|
226
243
|
pathname: entryPoint,
|
|
227
244
|
fullWrap: true,
|
|
228
245
|
});
|
|
229
|
-
replaceIframe(page.content);
|
|
246
|
+
await replaceIframe(page.content);
|
|
230
247
|
} else {
|
|
231
248
|
const page = await router.resolve({
|
|
232
249
|
pathname: "get/auth/login",
|
|
@@ -243,7 +260,7 @@
|
|
|
243
260
|
},
|
|
244
261
|
],
|
|
245
262
|
});
|
|
246
|
-
replaceIframe(page.content);
|
|
263
|
+
await replaceIframe(page.content);
|
|
247
264
|
console.error(error);
|
|
248
265
|
}
|
|
249
266
|
};
|
package/www/js/mocks/request.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
function MobileRequest(xhr = false, files = undefined) {
|
|
1
|
+
function MobileRequest({ xhr = false, files = undefined, query = undefined }) {
|
|
2
2
|
const roleId = saltcorn.data.state.getState().mobileConfig.role_id
|
|
3
3
|
? saltcorn.data.state.getState().mobileConfig.role_id
|
|
4
4
|
: 10;
|
|
@@ -26,5 +26,6 @@ function MobileRequest(xhr = false, files = undefined) {
|
|
|
26
26
|
csrfToken: () => "",
|
|
27
27
|
xhr,
|
|
28
28
|
files,
|
|
29
|
+
query,
|
|
29
30
|
};
|
|
30
31
|
}
|
package/www/js/routes/auth.js
CHANGED
|
@@ -87,7 +87,8 @@ const logoutAction = async () => {
|
|
|
87
87
|
const config = saltcorn.data.state.getState().mobileConfig;
|
|
88
88
|
const response = await apiCall({ method: "GET", path: "/auth/logout" });
|
|
89
89
|
if (response.data.success) {
|
|
90
|
-
|
|
90
|
+
await removeJwt();
|
|
91
|
+
config.jwt = undefined;
|
|
91
92
|
return {
|
|
92
93
|
content: renderLoginView(config.entry_point, config.version_tag),
|
|
93
94
|
};
|
package/www/js/routes/page.js
CHANGED
|
@@ -3,9 +3,9 @@ const postPageAction = async (context) => {
|
|
|
3
3
|
const state = saltcorn.data.state.getState();
|
|
4
4
|
const { page_name, rndid } = context.params;
|
|
5
5
|
const page = await saltcorn.data.models.Page.findOne({ name: page_name });
|
|
6
|
-
const req = new MobileRequest(context.xhr);
|
|
6
|
+
const req = new MobileRequest({ xhr: context.xhr });
|
|
7
7
|
if (state.mobileConfig.role_id > page.min_role) {
|
|
8
|
-
throw new Error(req.__("Not authorized"));
|
|
8
|
+
throw new Error(req.__("Not authorized"));
|
|
9
9
|
}
|
|
10
10
|
let col;
|
|
11
11
|
saltcorn.data.models.layout.traverseSync(page.layout, {
|
|
@@ -16,7 +16,7 @@ const postPageAction = async (context) => {
|
|
|
16
16
|
const result = await saltcorn.data.plugin_helper.run_action_column({
|
|
17
17
|
col,
|
|
18
18
|
referrer: "",
|
|
19
|
-
req
|
|
19
|
+
req,
|
|
20
20
|
});
|
|
21
21
|
return result || {};
|
|
22
22
|
};
|
|
@@ -26,9 +26,9 @@ const getPage = async (context) => {
|
|
|
26
26
|
const state = saltcorn.data.state.getState();
|
|
27
27
|
const { page_name } = context.params;
|
|
28
28
|
const page = await saltcorn.data.models.Page.findOne({ name: page_name });
|
|
29
|
-
const req = new MobileRequest(context.xhr);
|
|
29
|
+
const req = new MobileRequest({ xhr: context.xhr });
|
|
30
30
|
if (state.mobileConfig.role_id > page.min_role) {
|
|
31
|
-
throw new Error(req.__("Not authorized"));
|
|
31
|
+
throw new Error(req.__("Not authorized"));
|
|
32
32
|
}
|
|
33
33
|
const query = parseQuery(context.query);
|
|
34
34
|
const res = new MobileResponse();
|
package/www/js/routes/view.js
CHANGED
|
@@ -13,7 +13,7 @@ const postView = async (context) => {
|
|
|
13
13
|
const view = await saltcorn.data.models.View.findOne({
|
|
14
14
|
name: context.params.viewname,
|
|
15
15
|
});
|
|
16
|
-
const req = new MobileRequest(context.xhr, context.files);
|
|
16
|
+
const req = new MobileRequest({ xhr: context.xhr, files: context.files });
|
|
17
17
|
const res = new MobileResponse();
|
|
18
18
|
const state = saltcorn.data.state.getState();
|
|
19
19
|
if (
|
|
@@ -43,7 +43,7 @@ const postViewRoute = async (context) => {
|
|
|
43
43
|
const view = await saltcorn.data.models.View.findOne({
|
|
44
44
|
name: context.params.viewname,
|
|
45
45
|
});
|
|
46
|
-
const req = new MobileRequest(context.xhr);
|
|
46
|
+
const req = new MobileRequest({ xhr: context.xhr });
|
|
47
47
|
const res = new MobileResponse();
|
|
48
48
|
const state = saltcorn.data.state.getState();
|
|
49
49
|
if (state.mobileConfig.role_id > view.min_role) {
|
|
@@ -69,7 +69,7 @@ const getView = async (context) => {
|
|
|
69
69
|
const query = parseQuery(context.query);
|
|
70
70
|
const { viewname } = context.params;
|
|
71
71
|
const view = saltcorn.data.models.View.findOne({ name: viewname });
|
|
72
|
-
const req = new MobileRequest(context.xhr);
|
|
72
|
+
const req = new MobileRequest({ xhr: context.xhr, query });
|
|
73
73
|
if (
|
|
74
74
|
state.mobileConfig.role_id > view.min_role &&
|
|
75
75
|
!(await view.authorise_get({ query, req, ...view }))
|
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
"position: fixed; top: 0; left: 0; bottom: 0; right: 0; " +
|
|
3
|
-
"width: 100%; height: 100%; border: none; margin: 0; padding: 0; " +
|
|
4
|
-
"overflow: hidden; z-index: 999999; ";
|
|
5
|
-
|
|
6
|
-
const routingHistory = [];
|
|
1
|
+
let routingHistory = [];
|
|
7
2
|
|
|
8
3
|
function currentLocation() {
|
|
9
4
|
if (routingHistory.length == 0) return undefined;
|
|
@@ -28,7 +23,7 @@ async function apiCall({ method, path, params, body, responseType }) {
|
|
|
28
23
|
"X-Saltcorn-Client": "mobile-app",
|
|
29
24
|
};
|
|
30
25
|
if (config.tenantAppName) headers["X-Saltcorn-App"] = config.tenantAppName;
|
|
31
|
-
const token =
|
|
26
|
+
const token = config.jwt;
|
|
32
27
|
if (token) headers.Authorization = `jwt ${token}`;
|
|
33
28
|
try {
|
|
34
29
|
const result = await axios({
|
|
@@ -94,18 +89,11 @@ function splitPathQuery(url) {
|
|
|
94
89
|
return { path, query };
|
|
95
90
|
}
|
|
96
91
|
|
|
97
|
-
function replaceIframe(content) {
|
|
92
|
+
async function replaceIframe(content) {
|
|
93
|
+
await write("content.html", `${cordova.file.dataDirectory}`, content);
|
|
94
|
+
const url = await getDirEntry(`${cordova.file.dataDirectory}content.html`);
|
|
98
95
|
const iframe = document.getElementById("content-iframe");
|
|
99
|
-
iframe.
|
|
100
|
-
const newIframe = document.createElement("iframe");
|
|
101
|
-
document.body.appendChild(newIframe);
|
|
102
|
-
const config = saltcorn.data.state.getState().mobileConfig;
|
|
103
|
-
newIframe.contentWindow._sc_version_tag = config.version_tag;
|
|
104
|
-
newIframe.setAttribute("style", iframeStyle);
|
|
105
|
-
newIframe.id = "content-iframe";
|
|
106
|
-
newIframe.contentWindow.document.open();
|
|
107
|
-
newIframe.contentWindow.document.write(content);
|
|
108
|
-
newIframe.contentWindow.document.close();
|
|
96
|
+
iframe.src = url.toURL();
|
|
109
97
|
}
|
|
110
98
|
|
|
111
99
|
function addScriptToIframeHead(iframeDoc, script) {
|
|
@@ -190,6 +178,10 @@ async function goBack(steps = 1, exitOnFirstPage = false) {
|
|
|
190
178
|
await handleRoute("/");
|
|
191
179
|
} else {
|
|
192
180
|
routingHistory = routingHistory.slice(0, routingHistory.length - steps);
|
|
181
|
+
// don't repeat a post
|
|
182
|
+
if (routingHistory[routingHistory.length - 1].route.startsWith("post/")) {
|
|
183
|
+
routingHistory.pop();
|
|
184
|
+
}
|
|
193
185
|
const newCurrent = routingHistory.pop();
|
|
194
186
|
await handleRoute(newCurrent.route, newCurrent.query);
|
|
195
187
|
}
|
|
@@ -57,8 +57,13 @@ async function saveAndContinue(e, action, k) {
|
|
|
57
57
|
// TODO ch error (request.responseText?)
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
async function loginRequest(email, password, isSignup) {
|
|
61
|
-
const opts =
|
|
60
|
+
async function loginRequest({ email, password, isSignup, isPublic }) {
|
|
61
|
+
const opts = isPublic
|
|
62
|
+
? {
|
|
63
|
+
method: "GET",
|
|
64
|
+
path: "/auth/login-with/jwt",
|
|
65
|
+
}
|
|
66
|
+
: isSignup
|
|
62
67
|
? {
|
|
63
68
|
method: "POST",
|
|
64
69
|
path: "/auth/signup",
|
|
@@ -81,20 +86,21 @@ async function loginRequest(email, password, isSignup) {
|
|
|
81
86
|
|
|
82
87
|
async function login(e, entryPoint, isSignup) {
|
|
83
88
|
const formData = new FormData(e);
|
|
84
|
-
const loginResult = await loginRequest(
|
|
85
|
-
formData.get("email"),
|
|
86
|
-
formData.get("password"),
|
|
87
|
-
isSignup
|
|
88
|
-
);
|
|
89
|
+
const loginResult = await loginRequest({
|
|
90
|
+
email: formData.get("email"),
|
|
91
|
+
password: formData.get("password"),
|
|
92
|
+
isSignup,
|
|
93
|
+
});
|
|
89
94
|
if (typeof loginResult === "string") {
|
|
90
95
|
// use it as a token
|
|
91
|
-
parent.localStorage.setItem("auth_jwt", loginResult);
|
|
92
96
|
const decodedJwt = parent.jwt_decode(loginResult);
|
|
93
97
|
const config = parent.saltcorn.data.state.getState().mobileConfig;
|
|
94
98
|
config.role_id = decodedJwt.user.role_id ? decodedJwt.user.role_id : 10;
|
|
95
99
|
config.user_name = decodedJwt.user.email;
|
|
96
100
|
config.language = decodedJwt.user.language;
|
|
97
101
|
config.isPublicUser = false;
|
|
102
|
+
await parent.setJwt(loginResult);
|
|
103
|
+
config.jwt = loginResult;
|
|
98
104
|
await parent.i18next.changeLanguage(config.language);
|
|
99
105
|
parent.addRoute({ route: entryPoint, query: undefined });
|
|
100
106
|
const page = await parent.router.resolve({
|
|
@@ -110,7 +116,7 @@ async function login(e, entryPoint, isSignup) {
|
|
|
110
116
|
},
|
|
111
117
|
],
|
|
112
118
|
});
|
|
113
|
-
parent.replaceIframe(page.content);
|
|
119
|
+
await parent.replaceIframe(page.content);
|
|
114
120
|
} else if (loginResult?.alerts) {
|
|
115
121
|
parent.showAlerts(loginResult?.alerts);
|
|
116
122
|
} else {
|
|
@@ -120,23 +126,32 @@ async function login(e, entryPoint, isSignup) {
|
|
|
120
126
|
|
|
121
127
|
async function publicLogin(entryPoint) {
|
|
122
128
|
try {
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
129
|
+
const loginResult = await loginRequest({ isPublic: true });
|
|
130
|
+
if (typeof loginResult === "string") {
|
|
131
|
+
const config = parent.saltcorn.data.state.getState().mobileConfig;
|
|
132
|
+
config.role_id = 10;
|
|
133
|
+
config.user_name = "public";
|
|
134
|
+
config.language = "en";
|
|
135
|
+
config.isPublicUser = true;
|
|
136
|
+
await parent.setJwt(loginResult);
|
|
137
|
+
config.jwt = loginResult;
|
|
138
|
+
parent.i18next.changeLanguage(config.language);
|
|
139
|
+
const page = await parent.router.resolve({
|
|
140
|
+
pathname: entryPoint,
|
|
141
|
+
fullWrap: true,
|
|
142
|
+
alerts: [
|
|
143
|
+
{
|
|
144
|
+
type: "success",
|
|
145
|
+
msg: parent.i18next.t("Welcome to Saltcorn!"),
|
|
146
|
+
},
|
|
147
|
+
],
|
|
148
|
+
});
|
|
149
|
+
await parent.replaceIframe(page.content);
|
|
150
|
+
} else if (loginResult?.alerts) {
|
|
151
|
+
parent.showAlerts(loginResult?.alerts);
|
|
152
|
+
} else {
|
|
153
|
+
throw new Error("The login failed.");
|
|
154
|
+
}
|
|
140
155
|
} catch (error) {
|
|
141
156
|
parent.showAlerts([
|
|
142
157
|
{
|
|
@@ -155,7 +170,7 @@ async function logout() {
|
|
|
155
170
|
entryView: config.entry_point,
|
|
156
171
|
versionTag: config.version_tag,
|
|
157
172
|
});
|
|
158
|
-
parent.replaceIframe(page.content);
|
|
173
|
+
await parent.replaceIframe(page.content);
|
|
159
174
|
} catch (error) {
|
|
160
175
|
parent.showAlerts([
|
|
161
176
|
{
|
|
@@ -233,9 +248,22 @@ function updateQueryStringParameter(queryStr, key, value) {
|
|
|
233
248
|
return params.join("&");
|
|
234
249
|
}
|
|
235
250
|
|
|
251
|
+
function invalidate_pagings(currentQuery) {
|
|
252
|
+
let newQuery = currentQuery;
|
|
253
|
+
const queryObj = Object.fromEntries(new URLSearchParams(newQuery).entries());
|
|
254
|
+
const toRemove = Object.keys(queryObj).filter((val) => is_paging_param(val));
|
|
255
|
+
for (const k of toRemove) {
|
|
256
|
+
newQuery = removeQueryStringParameter(newQuery, k);
|
|
257
|
+
}
|
|
258
|
+
return newQuery;
|
|
259
|
+
}
|
|
260
|
+
|
|
236
261
|
async function set_state_fields(kvs, href) {
|
|
237
262
|
let queryParams = [];
|
|
238
263
|
let currentQuery = parent.currentQuery();
|
|
264
|
+
if (Object.keys(kvs).some((k) => !is_paging_param(k))) {
|
|
265
|
+
currentQuery = invalidate_pagings(currentQuery);
|
|
266
|
+
}
|
|
239
267
|
Object.entries(kvs).forEach((kv) => {
|
|
240
268
|
if (kv[1].unset && kv[1].unset === true) {
|
|
241
269
|
currentQuery = removeQueryStringParameter(currentQuery, kv[0]);
|
|
@@ -260,16 +288,23 @@ async function unset_state_field(key) {
|
|
|
260
288
|
await parent.handleRoute(href, query);
|
|
261
289
|
}
|
|
262
290
|
|
|
263
|
-
async function sortby(k, desc,
|
|
291
|
+
async function sortby(k, desc, viewIdentifier) {
|
|
264
292
|
await set_state_fields(
|
|
265
|
-
{
|
|
266
|
-
|
|
293
|
+
{
|
|
294
|
+
[`_${viewIdentifier}_sortby`]: k,
|
|
295
|
+
[`_${viewIdentifier}_sortdesc`]: desc ? "on" : { unset: true },
|
|
296
|
+
},
|
|
297
|
+
parent.currentLocation()
|
|
267
298
|
);
|
|
268
299
|
}
|
|
269
300
|
|
|
270
|
-
async function gopage(n, pagesize, extra) {
|
|
301
|
+
async function gopage(n, pagesize, viewIdentifier, extra) {
|
|
271
302
|
await set_state_fields(
|
|
272
|
-
{
|
|
303
|
+
{
|
|
304
|
+
...extra,
|
|
305
|
+
[`_${viewIdentifier}_page`]: n,
|
|
306
|
+
[`_${viewIdentifier}_pagesize`]: pagesize,
|
|
307
|
+
},
|
|
273
308
|
parent.currentLocation()
|
|
274
309
|
);
|
|
275
310
|
}
|
|
@@ -388,7 +423,7 @@ async function make_unique_field(
|
|
|
388
423
|
|
|
389
424
|
async function buildEncodedImage(fileId, elementId) {
|
|
390
425
|
const base64Encoded = await parent.loadEncodedFile(fileId);
|
|
391
|
-
|
|
426
|
+
document.getElementById(elementId).src = base64Encoded;
|
|
392
427
|
}
|
|
393
428
|
|
|
394
429
|
async function buildEncodedBgImage(fileId, elementId) {
|
|
@@ -400,11 +435,13 @@ async function buildEncodedBgImage(fileId, elementId) {
|
|
|
400
435
|
}
|
|
401
436
|
|
|
402
437
|
function openFile(fileId) {
|
|
438
|
+
// TODO fileIds with whitespaces do not work
|
|
403
439
|
const config = parent.saltcorn.data.state.getState().mobileConfig;
|
|
404
440
|
const serverPath = config.server_path;
|
|
405
|
-
const token =
|
|
441
|
+
const token = config.jwt;
|
|
442
|
+
const url = `${serverPath}/files/serve/${fileId}?jwt=${token}`;
|
|
406
443
|
parent.cordova.InAppBrowser.open(
|
|
407
|
-
|
|
444
|
+
url,
|
|
408
445
|
"_self",
|
|
409
446
|
"clearcache=yes,clearsessioncache=yes,location=no"
|
|
410
447
|
);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const historyFile = "update_history";
|
|
2
|
+
const jwtTableName = "jwt_table";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* drop tables that are no longer in the 'tables.json' file
|
|
@@ -7,14 +8,17 @@ const historyFile = "update_history";
|
|
|
7
8
|
async function dropDeletedTables(incomingTables) {
|
|
8
9
|
const existingTables = await saltcorn.data.models.Table.find();
|
|
9
10
|
for (const table of existingTables) {
|
|
10
|
-
if (
|
|
11
|
-
|
|
11
|
+
if (
|
|
12
|
+
table.name !== "users" &&
|
|
13
|
+
!incomingTables.find((row) => row.id === table.id)
|
|
14
|
+
) {
|
|
15
|
+
await saltcorn.data.db.query(`DROP TABLE ${table.name}`);
|
|
12
16
|
}
|
|
13
17
|
}
|
|
14
18
|
}
|
|
15
19
|
|
|
16
20
|
async function updateScTables(tablesJSON, skipScPlugins = true) {
|
|
17
|
-
saltcorn.data.db.query("PRAGMA foreign_keys = OFF;");
|
|
21
|
+
await saltcorn.data.db.query("PRAGMA foreign_keys = OFF;");
|
|
18
22
|
for (const { table, rows } of tablesJSON.sc_tables) {
|
|
19
23
|
if (skipScPlugins && table === "_sc_plugins") continue;
|
|
20
24
|
if (table === "_sc_tables") await dropDeletedTables(rows);
|
|
@@ -23,7 +27,7 @@ async function updateScTables(tablesJSON, skipScPlugins = true) {
|
|
|
23
27
|
await saltcorn.data.db.insert(table, row);
|
|
24
28
|
}
|
|
25
29
|
}
|
|
26
|
-
saltcorn.data.db.query("PRAGMA foreign_keys = ON;");
|
|
30
|
+
await saltcorn.data.db.query("PRAGMA foreign_keys = ON;");
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
async function updateScPlugins(tablesJSON) {
|
|
@@ -85,3 +89,23 @@ async function getTableIds(tableNames) {
|
|
|
85
89
|
.filter((table) => tableNames.indexOf(table.name) > -1)
|
|
86
90
|
.map((table) => table.id);
|
|
87
91
|
}
|
|
92
|
+
|
|
93
|
+
async function createJwtTable() {
|
|
94
|
+
await saltcorn.data.db.query(`CREATE TABLE IF NOT EXISTS ${jwtTableName} (
|
|
95
|
+
jwt VARCHAR(500)
|
|
96
|
+
)`);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function getJwt() {
|
|
100
|
+
const rows = await saltcorn.data.db.select(jwtTableName);
|
|
101
|
+
return rows?.length > 0 ? rows[0].jwt : null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async function removeJwt() {
|
|
105
|
+
await saltcorn.data.db.deleteWhere(jwtTableName);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async function setJwt(jwt) {
|
|
109
|
+
await removeJwt();
|
|
110
|
+
await saltcorn.data.db.insert(jwtTableName, { jwt: jwt });
|
|
111
|
+
}
|