@saltcorn/mobile-app 1.6.0-beta.5 → 1.6.0-beta.7
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/package.json +1 -1
- package/src/helpers/db_schema.js +68 -46
- package/src/helpers/offline_mode.js +35 -25
- package/src/init.js +0 -4
- package/src/routing/routes/api.js +3 -12
- package/src/routing/routes/delete.js +22 -12
- package/src/routing/routes/edit.js +2 -2
- package/src/routing/routes/fields.js +1 -4
- package/www/js/iframe_view_utils.js +1 -4
package/package.json
CHANGED
package/src/helpers/db_schema.js
CHANGED
|
@@ -102,49 +102,77 @@ export async function updateUserDefinedTables() {
|
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
+
const createSyncInfoIndexes = async (safeName) => {
|
|
106
|
+
const tbl = `${safeName}_sync_info`;
|
|
107
|
+
await saltcorn.data.db.query(
|
|
108
|
+
`CREATE INDEX IF NOT EXISTS ${tbl}_ref_index ON ${tbl}(ref)`
|
|
109
|
+
);
|
|
110
|
+
await saltcorn.data.db.query(
|
|
111
|
+
`CREATE INDEX IF NOT EXISTS ${tbl}_lm_index ON ${tbl}(last_modified)`
|
|
112
|
+
);
|
|
113
|
+
await saltcorn.data.db.query(
|
|
114
|
+
`CREATE INDEX IF NOT EXISTS ${tbl}_deleted_index ON ${tbl}(deleted)`
|
|
115
|
+
);
|
|
116
|
+
await saltcorn.data.db.query(
|
|
117
|
+
`CREATE INDEX IF NOT EXISTS ${tbl}_ml_index ON ${tbl}(modified_local)`
|
|
118
|
+
);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
// Each entry migrates sync_info tables from version (index) to version (index + 1).
|
|
122
|
+
// To add a migration: append a function and bump SYNC_INFO_SCHEMA_VERSION.
|
|
123
|
+
const SYNC_INFO_SCHEMA_VERSION = 1;
|
|
124
|
+
|
|
125
|
+
const syncInfoMigrations = [
|
|
126
|
+
// v0 → v1: ref integer → ref text (UUID primary key support)
|
|
127
|
+
// SQLite does not support ALTER COLUMN, so we rename → recreate → copy → drop
|
|
128
|
+
async (safeName) => {
|
|
129
|
+
const tbl = `${safeName}_sync_info`;
|
|
130
|
+
const tmp = `${tbl}_migrate_tmp`;
|
|
131
|
+
await saltcorn.data.db.query(`ALTER TABLE "${tbl}" RENAME TO "${tmp}"`);
|
|
132
|
+
await saltcorn.data.db.query(`CREATE TABLE "${tbl}" (
|
|
133
|
+
ref text,
|
|
134
|
+
last_modified timestamp,
|
|
135
|
+
deleted integer,
|
|
136
|
+
modified_local integer
|
|
137
|
+
)`);
|
|
138
|
+
await saltcorn.data.db.query(
|
|
139
|
+
`INSERT INTO "${tbl}" (ref, last_modified, deleted, modified_local)
|
|
140
|
+
SELECT CAST(ref AS TEXT), last_modified, deleted, modified_local FROM "${tmp}"`
|
|
141
|
+
);
|
|
142
|
+
await saltcorn.data.db.query(`DROP TABLE "${tmp}"`);
|
|
143
|
+
await createSyncInfoIndexes(safeName);
|
|
144
|
+
},
|
|
145
|
+
];
|
|
146
|
+
|
|
147
|
+
export async function migrateSyncInfoTables(synchTbls) {
|
|
148
|
+
const state = saltcorn.data.state.getState();
|
|
149
|
+
const currentVersion =
|
|
150
|
+
(await state.getConfig("sync_info_schema_version")) ?? -1;
|
|
151
|
+
if (currentVersion >= SYNC_INFO_SCHEMA_VERSION) return;
|
|
152
|
+
for (const synchTbl of synchTbls) {
|
|
153
|
+
const safeName = saltcorn.data.db.sqlsanitize(synchTbl);
|
|
154
|
+
if (!(await saltcorn.data.db.tableExists(`${safeName}_sync_info`)))
|
|
155
|
+
continue;
|
|
156
|
+
for (let v = currentVersion + 1; v <= SYNC_INFO_SCHEMA_VERSION; v++) {
|
|
157
|
+
await syncInfoMigrations[v - 1]?.(safeName);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
await state.setConfig("sync_info_schema_version", SYNC_INFO_SCHEMA_VERSION);
|
|
161
|
+
}
|
|
162
|
+
|
|
105
163
|
export async function createSyncInfoTables(synchTbls) {
|
|
106
|
-
|
|
107
|
-
name.endsWith("_sync_info");
|
|
108
|
-
});
|
|
164
|
+
await migrateSyncInfoTables(synchTbls);
|
|
109
165
|
for (const synchTbl of synchTbls) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
modified_local integer
|
|
166
|
+
const safeName = saltcorn.data.db.sqlsanitize(synchTbl);
|
|
167
|
+
const tblName = `${safeName}_sync_info`;
|
|
168
|
+
if (!(await saltcorn.data.db.tableExists(tblName))) {
|
|
169
|
+
await saltcorn.data.db.query(`CREATE TABLE IF NOT EXISTS ${tblName} (
|
|
170
|
+
ref text,
|
|
171
|
+
last_modified timestamp,
|
|
172
|
+
deleted integer,
|
|
173
|
+
modified_local integer
|
|
119
174
|
)`);
|
|
120
|
-
await
|
|
121
|
-
`CREATE INDEX IF NOT EXISTS ${saltcorn.data.db.sqlsanitize(
|
|
122
|
-
synchTbl
|
|
123
|
-
)}_sync_info_ref_index on ${saltcorn.data.db.sqlsanitize(
|
|
124
|
-
synchTbl
|
|
125
|
-
)}_sync_info(ref);`
|
|
126
|
-
);
|
|
127
|
-
await saltcorn.data.db.query(
|
|
128
|
-
`CREATE INDEX IF NOT EXISTS ${saltcorn.data.db.sqlsanitize(
|
|
129
|
-
synchTbl
|
|
130
|
-
)}_sync_info_lm_index on ${saltcorn.data.db.sqlsanitize(
|
|
131
|
-
synchTbl
|
|
132
|
-
)}_sync_info(last_modified);`
|
|
133
|
-
);
|
|
134
|
-
await saltcorn.data.db.query(
|
|
135
|
-
`CREATE INDEX IF NOT EXISTS ${saltcorn.data.db.sqlsanitize(
|
|
136
|
-
synchTbl
|
|
137
|
-
)}_sync_info_deleted_index on ${saltcorn.data.db.sqlsanitize(
|
|
138
|
-
synchTbl
|
|
139
|
-
)}_sync_info(deleted);`
|
|
140
|
-
);
|
|
141
|
-
await saltcorn.data.db.query(
|
|
142
|
-
`CREATE INDEX IF NOT EXISTS ${saltcorn.data.db.sqlsanitize(
|
|
143
|
-
synchTbl
|
|
144
|
-
)}_sync_info_ml_index on ${saltcorn.data.db.sqlsanitize(
|
|
145
|
-
synchTbl
|
|
146
|
-
)}_sync_info(modified_local);`
|
|
147
|
-
);
|
|
175
|
+
await createSyncInfoIndexes(safeName);
|
|
148
176
|
}
|
|
149
177
|
}
|
|
150
178
|
}
|
|
@@ -178,12 +206,6 @@ export async function updateDb(tablesJSON) {
|
|
|
178
206
|
});
|
|
179
207
|
}
|
|
180
208
|
|
|
181
|
-
export async function getTableIds(tableNames) {
|
|
182
|
-
return (await saltcorn.data.models.Table.find())
|
|
183
|
-
.filter((table) => tableNames.indexOf(table.name) > -1)
|
|
184
|
-
.map((table) => table.id);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
209
|
export async function createJwtTable() {
|
|
188
210
|
await saltcorn.data.db.query(`CREATE TABLE IF NOT EXISTS ${jwtTableName} (
|
|
189
211
|
jwt VARCHAR(500)
|
|
@@ -11,6 +11,9 @@ import {
|
|
|
11
11
|
removeLoadSpinner,
|
|
12
12
|
} from "./common";
|
|
13
13
|
|
|
14
|
+
// Safely embed a ref value (integer or UUID string) in raw SQL
|
|
15
|
+
const sqlRef = (ref) => `'${String(ref).replace(/'/g, "''")}'`;
|
|
16
|
+
|
|
14
17
|
const setUploadStarted = async (started, time) => {
|
|
15
18
|
const state = saltcorn.data.state.getState();
|
|
16
19
|
const oldSession = await state.getConfig("last_offline_session");
|
|
@@ -35,7 +38,7 @@ const prepare = async () => {
|
|
|
35
38
|
const { synchedTables } = state.mobileConfig;
|
|
36
39
|
const syncInfos = {};
|
|
37
40
|
for (const tblName of synchedTables) {
|
|
38
|
-
const syncInfo = {
|
|
41
|
+
const syncInfo = { lastModifiedAt: 0, lastRef: "" };
|
|
39
42
|
const maxLm = await maxLastModified(tblName);
|
|
40
43
|
if (maxLm) syncInfo.syncFrom = maxLm.valueOf();
|
|
41
44
|
syncInfos[tblName] = syncInfo;
|
|
@@ -59,20 +62,20 @@ const insertRemoteData = async (table, rows, syncTimestamp) => {
|
|
|
59
62
|
const infos = await saltcorn.data.db.select(
|
|
60
63
|
`${saltcorn.data.db.sqlsanitize(tblName)}_sync_info`,
|
|
61
64
|
{
|
|
62
|
-
ref: rest[pkName],
|
|
65
|
+
ref: String(rest[pkName]),
|
|
63
66
|
}
|
|
64
67
|
);
|
|
65
68
|
if (infos.length > 0) {
|
|
66
69
|
await saltcorn.data.db.query(
|
|
67
70
|
`update "${saltcorn.data.db.sqlsanitize(tblName)}_sync_info"
|
|
68
71
|
set last_modified=${last_modified}, deleted=false, modified_local = false
|
|
69
|
-
where ref=${rest[pkName]}`
|
|
72
|
+
where ref=${sqlRef(rest[pkName])}`
|
|
70
73
|
);
|
|
71
74
|
} else {
|
|
72
75
|
await saltcorn.data.db.insert(
|
|
73
76
|
`${saltcorn.data.db.sqlsanitize(tblName)}_sync_info`,
|
|
74
77
|
{
|
|
75
|
-
ref,
|
|
78
|
+
ref: String(ref),
|
|
76
79
|
last_modified: syncTimestamp,
|
|
77
80
|
deleted: false,
|
|
78
81
|
modified_local: false,
|
|
@@ -103,14 +106,15 @@ const syncRemoteData = async (syncInfos, syncTimestamp) => {
|
|
|
103
106
|
loadUntil: syncTimestamp,
|
|
104
107
|
},
|
|
105
108
|
});
|
|
106
|
-
for (const [tblName, { rows,
|
|
109
|
+
for (const [tblName, { rows, maxModifiedAt, maxRef }] of Object.entries(
|
|
107
110
|
loadResp.data
|
|
108
111
|
)) {
|
|
109
112
|
if (rows?.length > 0) {
|
|
110
113
|
const table = getTable(tblName);
|
|
111
114
|
hasMoreData = true;
|
|
112
115
|
await insertRemoteData(table, rows, syncTimestamp);
|
|
113
|
-
syncInfos[tblName].
|
|
116
|
+
syncInfos[tblName].lastModifiedAt = maxModifiedAt ?? 0;
|
|
117
|
+
syncInfos[tblName].lastRef = maxRef ?? "";
|
|
114
118
|
}
|
|
115
119
|
}
|
|
116
120
|
}
|
|
@@ -123,7 +127,7 @@ const prepDeletes = async (table, deletes) => {
|
|
|
123
127
|
// don't delete if it's local modifed or unsynched
|
|
124
128
|
const tblConflicts = await saltcorn.data.db.query(
|
|
125
129
|
`select ref from "${saltcorn.data.db.sqlsanitize(tblName)}_sync_info"
|
|
126
|
-
where ref in (${deletes.map(({ ref }) => ref).join(",")}) and
|
|
130
|
+
where ref in (${deletes.map(({ ref }) => sqlRef(ref)).join(",")}) and
|
|
127
131
|
(last_modified is null or modified_local = true)`
|
|
128
132
|
);
|
|
129
133
|
if (tblConflicts.rows.length > 0) {
|
|
@@ -132,7 +136,7 @@ const prepDeletes = async (table, deletes) => {
|
|
|
132
136
|
await saltcorn.data.db.query(
|
|
133
137
|
`update "${saltcorn.data.db.sqlsanitize(tblName)}_sync_info"
|
|
134
138
|
set last_modified = null, modified_local = true
|
|
135
|
-
where ref in (${conflicts.join(",")})`
|
|
139
|
+
where ref in (${conflicts.map(sqlRef).join(",")})`
|
|
136
140
|
);
|
|
137
141
|
const conflictsSet = new Set(conflicts);
|
|
138
142
|
result = result.filter((del) => !conflictsSet.has(del.ref));
|
|
@@ -153,10 +157,12 @@ const prepDeletes = async (table, deletes) => {
|
|
|
153
157
|
)}" as data_tbl join "${saltcorn.data.db.sqlsanitize(
|
|
154
158
|
srcTbl.name
|
|
155
159
|
)}_sync_info" as info_tbl
|
|
156
|
-
on data_tbl."${saltcorn.data.db.sqlsanitize(
|
|
160
|
+
on CAST(info_tbl.ref AS TEXT) = CAST(data_tbl."${saltcorn.data.db.sqlsanitize(
|
|
161
|
+
pkName
|
|
162
|
+
)}" AS TEXT)
|
|
157
163
|
where data_tbl."${saltcorn.data.db.sqlsanitize(
|
|
158
164
|
field.name
|
|
159
|
-
)}" in (${result.map(({ ref }) => ref).join(",")})
|
|
165
|
+
)}" in (${result.map(({ ref }) => sqlRef(ref)).join(",")})
|
|
160
166
|
and (info_tbl.last_modified is null or info_tbl.modified_local = true)`
|
|
161
167
|
);
|
|
162
168
|
if (fkConflicts.rows.length > 0) {
|
|
@@ -164,12 +170,12 @@ const prepDeletes = async (table, deletes) => {
|
|
|
164
170
|
const conflicts = fkConflicts.rows.map(
|
|
165
171
|
(conflict) => conflict[field.name]
|
|
166
172
|
);
|
|
167
|
-
const conflictsSet = new Set(conflicts);
|
|
168
|
-
result = result.filter((del) => !conflictsSet.has(del.ref));
|
|
173
|
+
const conflictsSet = new Set(conflicts.map(String));
|
|
174
|
+
result = result.filter((del) => !conflictsSet.has(String(del.ref)));
|
|
169
175
|
await saltcorn.data.db.query(
|
|
170
176
|
`update "${saltcorn.data.db.sqlsanitize(tblName)}_sync_info"
|
|
171
177
|
set last_modified = null, modified_local = true
|
|
172
|
-
where ref in (${conflicts.join(",")})`
|
|
178
|
+
where ref in (${conflicts.map(sqlRef).join(",")})`
|
|
173
179
|
);
|
|
174
180
|
}
|
|
175
181
|
}
|
|
@@ -184,16 +190,16 @@ const applyDeletes = async (allDeletes, syncTimestamp) => {
|
|
|
184
190
|
const pkName = table.pk_name;
|
|
185
191
|
const safeDeletes = await prepDeletes(table, deletes);
|
|
186
192
|
if (safeDeletes.length > 0) {
|
|
187
|
-
const
|
|
193
|
+
const delRefs = safeDeletes.map(({ ref }) => sqlRef(ref)).join(",");
|
|
188
194
|
await saltcorn.data.db.query(
|
|
189
195
|
`delete from "${saltcorn.data.db.sqlsanitize(
|
|
190
196
|
tblName
|
|
191
|
-
)}" where "${saltcorn.data.db.sqlsanitize(pkName)}" in (${
|
|
197
|
+
)}" where "${saltcorn.data.db.sqlsanitize(pkName)}" in (${delRefs})`
|
|
192
198
|
);
|
|
193
199
|
await saltcorn.data.db.query(
|
|
194
200
|
`update "${saltcorn.data.db.sqlsanitize(tblName)}_sync_info"
|
|
195
201
|
set deleted = true, last_modified = ${syncTimestamp}, modified_local = false
|
|
196
|
-
where ref in (${
|
|
202
|
+
where ref in (${delRefs}) and deleted = false`
|
|
197
203
|
);
|
|
198
204
|
}
|
|
199
205
|
}
|
|
@@ -226,9 +232,11 @@ const loadOfflineChanges = async (synchedTbls) => {
|
|
|
226
232
|
from "${saltcorn.data.db.sqlsanitize(
|
|
227
233
|
synchedTbl
|
|
228
234
|
)}_sync_info" as info_tbl left join "${saltcorn.data.db.sqlsanitize(
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
on info_tbl.ref = data_tbl."${saltcorn.data.db.sqlsanitize(
|
|
235
|
+
synchedTbl
|
|
236
|
+
)}" as data_tbl
|
|
237
|
+
on CAST(info_tbl.ref AS TEXT) = CAST(data_tbl."${saltcorn.data.db.sqlsanitize(
|
|
238
|
+
pkName
|
|
239
|
+
)}" AS TEXT)
|
|
232
240
|
where info_tbl.modified_local = true`
|
|
233
241
|
);
|
|
234
242
|
const inserts = [];
|
|
@@ -280,8 +288,8 @@ const handleTranslatedIds = async (allUniqueConflicts, allTranslations) => {
|
|
|
280
288
|
await saltcorn.data.db.update(tblName, { [table.pk_name]: to }, from);
|
|
281
289
|
await saltcorn.data.db.query(
|
|
282
290
|
`update "${saltcorn.data.db.sqlsanitize(tblName)}_sync_info"
|
|
283
|
-
set ref = ${to}
|
|
284
|
-
where ref = ${from} and deleted = false`
|
|
291
|
+
set ref = ${sqlRef(to)}
|
|
292
|
+
where ref = ${sqlRef(from)} and deleted = false`
|
|
285
293
|
);
|
|
286
294
|
}
|
|
287
295
|
for (const fk of fks) {
|
|
@@ -311,7 +319,7 @@ const handleUniqueConflicts = async (uniqueConflicts, translatedIds) => {
|
|
|
311
319
|
if (to === conflict[pkName]) {
|
|
312
320
|
await table.deleteRows({ [pkName]: from });
|
|
313
321
|
await saltcorn.data.db.deleteWhere(`${table.name}_sync_info`, {
|
|
314
|
-
ref: from,
|
|
322
|
+
ref: String(from),
|
|
315
323
|
});
|
|
316
324
|
}
|
|
317
325
|
}
|
|
@@ -376,11 +384,11 @@ const updateSyncInfos = async (
|
|
|
376
384
|
)
|
|
377
385
|
);
|
|
378
386
|
const values = refIds.map(
|
|
379
|
-
(ref) => `(${ref}, ${syncTimestamp}, ${deleted}, false)`
|
|
387
|
+
(ref) => `(${sqlRef(ref)}, ${syncTimestamp}, ${deleted}, false)`
|
|
380
388
|
);
|
|
381
389
|
await saltcorn.data.db.query(
|
|
382
390
|
`delete from "${saltcorn.data.db.sqlsanitize(tblName)}_sync_info"
|
|
383
|
-
where ref in (${refIds.join(",")})`
|
|
391
|
+
where ref in (${refIds.map(sqlRef).join(",")})`
|
|
384
392
|
);
|
|
385
393
|
await saltcorn.data.db.query(
|
|
386
394
|
`insert into "${saltcorn.data.db.sqlsanitize(tblName)}_sync_info"
|
|
@@ -714,7 +722,9 @@ export async function hasOfflineRows() {
|
|
|
714
722
|
tblName
|
|
715
723
|
)}_sync_info" as info_tbl
|
|
716
724
|
join "${saltcorn.data.db.sqlsanitize(tblName)}" as data_tbl
|
|
717
|
-
on info_tbl.ref = data_tbl."${saltcorn.data.db.sqlsanitize(
|
|
725
|
+
on CAST(info_tbl.ref AS TEXT) = CAST(data_tbl."${saltcorn.data.db.sqlsanitize(
|
|
726
|
+
pkName
|
|
727
|
+
)}" AS TEXT)
|
|
718
728
|
where info_tbl.modified_local = true`
|
|
719
729
|
);
|
|
720
730
|
if (rows?.length > 0 && parseInt(rows[0].total) > 0) return true;
|
package/src/init.js
CHANGED
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
createSyncInfoTables,
|
|
12
12
|
dbUpdateNeeded,
|
|
13
13
|
updateDb,
|
|
14
|
-
getTableIds,
|
|
15
14
|
createJwtTable,
|
|
16
15
|
} from "./helpers/db_schema.js";
|
|
17
16
|
import { publicLogin, checkJWT } from "./helpers/auth.js";
|
|
@@ -438,9 +437,6 @@ export async function init(mobileConfig) {
|
|
|
438
437
|
await state.refresh_triggers();
|
|
439
438
|
await state.refresh_config();
|
|
440
439
|
await state.refresh_codepages();
|
|
441
|
-
state.mobileConfig.localTableIds = await getTableIds(
|
|
442
|
-
mobileConfig.localUserTables
|
|
443
|
-
);
|
|
444
440
|
await state.setConfig("base_url", mobileConfig.server_path);
|
|
445
441
|
await initI18Next();
|
|
446
442
|
state.mobileConfig.encodedSiteLogo = await readSiteLogo();
|
|
@@ -14,10 +14,7 @@ export const loadTableRows = async (context) => {
|
|
|
14
14
|
const mobileConfig = saltcorn.data.state.getState().mobileConfig;
|
|
15
15
|
const table = saltcorn.data.models.Table.findOne({ name: tableName });
|
|
16
16
|
if (!table) throw new Error(`The table '${tableName}' does not exist.`);
|
|
17
|
-
if (
|
|
18
|
-
mobileConfig.isOfflineMode ||
|
|
19
|
-
mobileConfig.localTableIds.indexOf(table.id) >= 0
|
|
20
|
-
) {
|
|
17
|
+
if (mobileConfig.isOfflineMode) {
|
|
21
18
|
const rows = await table.getRows(query, {
|
|
22
19
|
orderBy: table.pk_name,
|
|
23
20
|
forUser: mobileConfig.user,
|
|
@@ -38,10 +35,7 @@ export const updateTableRow = async (context) => {
|
|
|
38
35
|
const mobileConfig = saltcorn.data.state.getState().mobileConfig;
|
|
39
36
|
const table = saltcorn.data.models.Table.findOne({ name: tableName });
|
|
40
37
|
if (!table) throw new Error(`The table '${tableName}' does not exist.`);
|
|
41
|
-
if (
|
|
42
|
-
mobileConfig.isOfflineMode ||
|
|
43
|
-
mobileConfig.localTableIds.indexOf(table.id) >= 0
|
|
44
|
-
) {
|
|
38
|
+
if (mobileConfig.isOfflineMode) {
|
|
45
39
|
const row = {};
|
|
46
40
|
for (const [k, v] of new URLSearchParams(context.query).entries()) {
|
|
47
41
|
row[k] = v;
|
|
@@ -73,10 +67,7 @@ export const insertTableRow = async (context) => {
|
|
|
73
67
|
const table = saltcorn.data.models.Table.findOne({ name: tableName });
|
|
74
68
|
const mobileConfig = saltcorn.data.state.getState().mobileConfig;
|
|
75
69
|
if (!table) throw new Error(`The table '${tableName}' does not exist.`);
|
|
76
|
-
if (
|
|
77
|
-
mobileConfig.isOfflineMode ||
|
|
78
|
-
mobileConfig.localTableIds.indexOf(table.id) >= 0
|
|
79
|
-
) {
|
|
70
|
+
if (mobileConfig.isOfflineMode) {
|
|
80
71
|
const row = {};
|
|
81
72
|
for (const [k, v] of new URLSearchParams(context.query).entries()) {
|
|
82
73
|
row[k] = v;
|
|
@@ -7,19 +7,29 @@ import i18next from "i18next";
|
|
|
7
7
|
export const deleteRows = async (context) => {
|
|
8
8
|
const { tableName, id } = context.params;
|
|
9
9
|
const table = await saltcorn.data.models.Table.findOne({ name: tableName });
|
|
10
|
-
const { isOfflineMode,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
} else
|
|
10
|
+
const { isOfflineMode, user } = saltcorn.data.state.getState().mobileConfig;
|
|
11
|
+
if (isOfflineMode) {
|
|
12
|
+
const role = user?.role_id || 100;
|
|
13
|
+
const where = { [table.pk_name]: id };
|
|
14
|
+
if (role <= table.min_role_write) {
|
|
15
|
+
await table.deleteRows(where, user);
|
|
16
|
+
} else if ((table.ownership_field_id || table.ownership_formula) && user) {
|
|
17
|
+
const row = await table.getJoinedRow({
|
|
18
|
+
where,
|
|
19
|
+
forUser: user,
|
|
20
|
+
forPublic: !user,
|
|
21
|
+
});
|
|
22
|
+
if (row && table.is_owner(user, row)) {
|
|
23
|
+
await table.deleteRows(where, user);
|
|
24
|
+
} else {
|
|
25
|
+
throw new saltcorn.data.utils.NotAuthorized(
|
|
26
|
+
i18next.t("Not authorized")
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
} else {
|
|
17
30
|
throw new saltcorn.data.utils.NotAuthorized(i18next.t("Not authorized"));
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
// if (isOfflineMode && !(await offlineHelper.hasOfflineRows())) {
|
|
21
|
-
// await offlineHelper.setOfflineSession(null);
|
|
22
|
-
// }
|
|
31
|
+
}
|
|
32
|
+
if (await hasOfflineRows()) await setHasOfflineData(true);
|
|
23
33
|
} else {
|
|
24
34
|
await apiCall({ method: "POST", path: `/delete/${tableName}/${id}` });
|
|
25
35
|
}
|
|
@@ -8,8 +8,8 @@ export const postToggleField = async (context) => {
|
|
|
8
8
|
const { name, id, field_name } = context.params;
|
|
9
9
|
const table = await saltcorn.data.models.Table.findOne({ name });
|
|
10
10
|
const state = saltcorn.data.state.getState();
|
|
11
|
-
const { isOfflineMode,
|
|
12
|
-
if (isOfflineMode
|
|
11
|
+
const { isOfflineMode, user } = state.mobileConfig;
|
|
12
|
+
if (isOfflineMode) {
|
|
13
13
|
if (user.role_id > table.min_role_write)
|
|
14
14
|
throw new saltcorn.data.utils.NotAuthorized(i18next.t("Not authorized"));
|
|
15
15
|
await table.toggleBool(+id, field_name, user);
|
|
@@ -10,10 +10,7 @@ export const postShowCalculated = async (context) => {
|
|
|
10
10
|
const mobileConfig = saltcorn.data.state.getState().mobileConfig;
|
|
11
11
|
const table = saltcorn.data.models.Table.findOne({ name: tableName });
|
|
12
12
|
if (!table) throw new Error(`The table '${tableName}' does not exist.`);
|
|
13
|
-
if (
|
|
14
|
-
mobileConfig.isOfflineMode ||
|
|
15
|
-
mobileConfig.localTableIds.indexOf(table.id) >= 0
|
|
16
|
-
) {
|
|
13
|
+
if (mobileConfig.isOfflineMode) {
|
|
17
14
|
const req = new MobileRequest({
|
|
18
15
|
query: context.query ? parseQuery(context.query) : {},
|
|
19
16
|
body: context.data || {},
|
|
@@ -783,10 +783,7 @@ async function view_post(viewnameOrElem, route, data, onDone, sendState) {
|
|
|
783
783
|
showLoadSpinner();
|
|
784
784
|
let respData = undefined;
|
|
785
785
|
const query = sendState ? buildQuery() : "";
|
|
786
|
-
if (
|
|
787
|
-
mobileConfig.isOfflineMode ||
|
|
788
|
-
(view?.table_id && mobileConfig.localTableIds.indexOf(view.table_id) >= 0)
|
|
789
|
-
) {
|
|
786
|
+
if (mobileConfig.isOfflineMode) {
|
|
790
787
|
respData = await parent.saltcorn.mobileApp.navigation.router.resolve({
|
|
791
788
|
pathname: `post/view/${viewname}/${route}`,
|
|
792
789
|
data,
|