dbgate-api-premium 6.3.2 → 6.4.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.
Files changed (46) hide show
  1. package/package.json +9 -7
  2. package/src/auth/storageAuthProvider.js +2 -1
  3. package/src/controllers/archive.js +99 -6
  4. package/src/controllers/auth.js +3 -1
  5. package/src/controllers/config.js +135 -22
  6. package/src/controllers/connections.js +35 -2
  7. package/src/controllers/databaseConnections.js +101 -2
  8. package/src/controllers/files.js +59 -0
  9. package/src/controllers/jsldata.js +9 -0
  10. package/src/controllers/runners.js +25 -5
  11. package/src/controllers/serverConnections.js +22 -2
  12. package/src/controllers/storage.js +341 -8
  13. package/src/controllers/storageDb.js +59 -1
  14. package/src/controllers/uploads.js +0 -46
  15. package/src/currentVersion.js +2 -2
  16. package/src/main.js +7 -1
  17. package/src/proc/connectProcess.js +14 -2
  18. package/src/proc/databaseConnectionProcess.js +70 -5
  19. package/src/proc/serverConnectionProcess.js +7 -1
  20. package/src/proc/sessionProcess.js +15 -178
  21. package/src/shell/archiveReader.js +3 -1
  22. package/src/shell/collectorWriter.js +2 -2
  23. package/src/shell/copyStream.js +1 -0
  24. package/src/shell/dataReplicator.js +96 -0
  25. package/src/shell/download.js +22 -6
  26. package/src/shell/index.js +12 -2
  27. package/src/shell/jsonLinesWriter.js +4 -3
  28. package/src/shell/queryReader.js +10 -3
  29. package/src/shell/unzipDirectory.js +91 -0
  30. package/src/shell/unzipJsonLinesData.js +60 -0
  31. package/src/shell/unzipJsonLinesFile.js +59 -0
  32. package/src/shell/zipDirectory.js +49 -0
  33. package/src/shell/zipJsonLinesData.js +49 -0
  34. package/src/utility/DatastoreProxy.js +4 -0
  35. package/src/utility/cloudUpgrade.js +14 -1
  36. package/src/utility/connectUtility.js +3 -1
  37. package/src/utility/crypting.js +137 -22
  38. package/src/utility/extractSingleFileFromZip.js +77 -0
  39. package/src/utility/getMapExport.js +2 -0
  40. package/src/utility/handleQueryStream.js +186 -0
  41. package/src/utility/healthStatus.js +12 -1
  42. package/src/utility/listZipEntries.js +41 -0
  43. package/src/utility/processArgs.js +5 -0
  44. package/src/utility/sshTunnel.js +13 -2
  45. package/src/utility/storageReplicatorItems.js +88 -0
  46. package/src/shell/dataDuplicator.js +0 -61
@@ -9,6 +9,9 @@ const scheduler = require('./scheduler');
9
9
  const getDiagramExport = require('../utility/getDiagramExport');
10
10
  const apps = require('./apps');
11
11
  const getMapExport = require('../utility/getMapExport');
12
+ const dbgateApi = require('../shell');
13
+ const { getLogger } = require('dbgate-tools');
14
+ const logger = getLogger('files');
12
15
 
13
16
  function serialize(format, data) {
14
17
  if (format == 'text') return data;
@@ -219,4 +222,60 @@ module.exports = {
219
222
  return path.join(dir, file);
220
223
  }
221
224
  },
225
+
226
+ createZipFromJsons_meta: true,
227
+ async createZipFromJsons({ db, filePath }) {
228
+ logger.info(`Creating zip file from JSONS ${filePath}`);
229
+ await dbgateApi.zipJsonLinesData(db, filePath);
230
+ return true;
231
+ },
232
+
233
+ getJsonsFromZip_meta: true,
234
+ async getJsonsFromZip({ filePath }) {
235
+ const res = await dbgateApi.unzipJsonLinesData(filePath);
236
+ return res;
237
+ },
238
+
239
+ downloadText_meta: true,
240
+ async downloadText({ uri }, req) {
241
+ if (!uri) return null;
242
+ const filePath = await dbgateApi.download(uri);
243
+ const text = await fs.readFile(filePath, {
244
+ encoding: 'utf-8',
245
+ });
246
+ return text;
247
+ },
248
+
249
+ saveUploadedFile_meta: true,
250
+ async saveUploadedFile({ filePath, fileName }) {
251
+ const FOLDERS = ['sql', 'sqlite'];
252
+ for (const folder of FOLDERS) {
253
+ if (fileName.toLowerCase().endsWith('.' + folder)) {
254
+ logger.info(`Saving ${folder} file ${fileName}`);
255
+ await fs.copyFile(filePath, path.join(filesdir(), folder, fileName));
256
+
257
+ socket.emitChanged(`files-changed`, { folder: folder });
258
+ socket.emitChanged(`all-files-changed`);
259
+ return {
260
+ name: path.basename(filePath),
261
+ folder: folder,
262
+ };
263
+ }
264
+ }
265
+
266
+ throw new Error(`${fileName} doesn't have one of supported extensions: ${FOLDERS.join(', ')}`);
267
+ },
268
+
269
+ exportFile_meta: true,
270
+ async exportFile({ folder, file, filePath }, req) {
271
+ if (!hasPermission(`files/${folder}/read`, req)) return false;
272
+ await fs.copyFile(path.join(filesdir(), folder, file), filePath);
273
+ return true;
274
+ },
275
+
276
+ simpleCopy_meta: true,
277
+ async simpleCopy({ sourceFilePath, targetFilePath }, req) {
278
+ await fs.copyFile(sourceFilePath, targetFilePath);
279
+ return true;
280
+ },
222
281
  };
@@ -8,6 +8,8 @@ const getJslFileName = require('../utility/getJslFileName');
8
8
  const JsonLinesDatastore = require('../utility/JsonLinesDatastore');
9
9
  const requirePluginFunction = require('../utility/requirePluginFunction');
10
10
  const socket = require('../utility/socket');
11
+ const crypto = require('crypto');
12
+ const dbgateApi = require('../shell');
11
13
 
12
14
  function readFirstLine(file) {
13
15
  return new Promise((resolve, reject) => {
@@ -293,4 +295,11 @@ module.exports = {
293
295
  })),
294
296
  };
295
297
  },
298
+
299
+ downloadJslData_meta: true,
300
+ async downloadJslData({ uri }) {
301
+ const jslid = crypto.randomUUID();
302
+ await dbgateApi.download(uri, { targetFile: getJslFileName(jslid) });
303
+ return { jslid };
304
+ },
296
305
  };
@@ -8,7 +8,7 @@ const { fork, spawn } = require('child_process');
8
8
  const { rundir, uploadsdir, pluginsdir, getPluginBackendPath, packagedPluginList } = require('../utility/directories');
9
9
  const {
10
10
  extractShellApiPlugins,
11
- extractShellApiFunctionName,
11
+ compileShellApiFunctionName,
12
12
  jsonScriptToJavascript,
13
13
  getLogger,
14
14
  safeJsonParse,
@@ -58,7 +58,7 @@ dbgateApi.initializeApiEnvironment();
58
58
  ${requirePluginsTemplate(extractShellApiPlugins(functionName, props))}
59
59
  require=null;
60
60
  async function run() {
61
- const reader=await ${extractShellApiFunctionName(functionName)}(${JSON.stringify(props)});
61
+ const reader=await ${compileShellApiFunctionName(functionName)}(${JSON.stringify(props)});
62
62
  const writer=await dbgateApi.collectorWriter({runid: '${runid}'});
63
63
  await dbgateApi.copyStream(reader, writer);
64
64
  }
@@ -96,9 +96,9 @@ module.exports = {
96
96
 
97
97
  handle_ping() {},
98
98
 
99
- handle_freeData(runid, { freeData }) {
99
+ handle_dataResult(runid, { dataResult }) {
100
100
  const { resolve } = this.requests[runid];
101
- resolve(freeData);
101
+ resolve(dataResult);
102
102
  delete this.requests[runid];
103
103
  },
104
104
 
@@ -273,7 +273,7 @@ module.exports = {
273
273
  const runid = crypto.randomUUID();
274
274
 
275
275
  if (script.type == 'json') {
276
- const js = jsonScriptToJavascript(script);
276
+ const js = await jsonScriptToJavascript(script);
277
277
  return this.startCore(runid, scriptTemplate(js, false));
278
278
  }
279
279
 
@@ -328,4 +328,24 @@ module.exports = {
328
328
  });
329
329
  return promise;
330
330
  },
331
+
332
+ scriptResult_meta: true,
333
+ async scriptResult({ script }) {
334
+ if (script.type != 'json') {
335
+ return { errorMessage: 'Only JSON scripts are allowed' };
336
+ }
337
+
338
+ const promise = new Promise(async (resolve, reject) => {
339
+ const runid = crypto.randomUUID();
340
+ this.requests[runid] = { resolve, reject, exitOnStreamError: true };
341
+ const cloned = _.cloneDeepWith(script, node => {
342
+ if (node?.$replace == 'runid') {
343
+ return runid;
344
+ }
345
+ });
346
+ const js = await jsonScriptToJavascript(cloned);
347
+ this.startCore(runid, scriptTemplate(js, false));
348
+ });
349
+ return promise;
350
+ },
331
351
  };
@@ -54,6 +54,9 @@ module.exports = {
54
54
  if (!connection) {
55
55
  throw new Error(`Connection with conid="${conid}" not found`);
56
56
  }
57
+ if (connection.singleDatabase) {
58
+ return null;
59
+ }
57
60
  if (connection.passwordMode == 'askPassword' || connection.passwordMode == 'askUser') {
58
61
  throw new MissingCredentialsError({ conid, passwordMode: connection.passwordMode });
59
62
  }
@@ -98,6 +101,11 @@ module.exports = {
98
101
  if (newOpened.disconnected) return;
99
102
  this.close(conid, false);
100
103
  });
104
+ subprocess.on('error', err => {
105
+ logger.error(extractErrorLogData(err), 'Error in server connection subprocess');
106
+ if (newOpened.disconnected) return;
107
+ this.close(conid, false);
108
+ });
101
109
  subprocess.send({ msgtype: 'connect', ...connection, globalSettings: await config.getSettings() });
102
110
  return newOpened;
103
111
  });
@@ -137,14 +145,14 @@ module.exports = {
137
145
  if (conid == '__model') return [];
138
146
  testConnectionPermission(conid, req);
139
147
  const opened = await this.ensureOpened(conid);
140
- return opened.databases;
148
+ return opened?.databases ?? [];
141
149
  },
142
150
 
143
151
  version_meta: true,
144
152
  async version({ conid }, req) {
145
153
  testConnectionPermission(conid, req);
146
154
  const opened = await this.ensureOpened(conid);
147
- return opened.version;
155
+ return opened?.version ?? null;
148
156
  },
149
157
 
150
158
  serverStatus_meta: true,
@@ -165,6 +173,9 @@ module.exports = {
165
173
  }
166
174
  this.lastPinged[conid] = new Date().getTime();
167
175
  const opened = await this.ensureOpened(conid);
176
+ if (!opened) {
177
+ return Promise.resolve();
178
+ }
168
179
  try {
169
180
  opened.subprocess.send({ msgtype: 'ping' });
170
181
  } catch (err) {
@@ -189,6 +200,9 @@ module.exports = {
189
200
  async sendDatabaseOp({ conid, msgtype, name }, req) {
190
201
  testConnectionPermission(conid, req);
191
202
  const opened = await this.ensureOpened(conid);
203
+ if (!opened) {
204
+ return null;
205
+ }
192
206
  if (opened.connection.isReadOnly) return false;
193
207
  const res = await this.sendRequest(opened, { msgtype, name });
194
208
  if (res.errorMessage) {
@@ -228,6 +242,9 @@ module.exports = {
228
242
  async loadDataCore(msgtype, { conid, ...args }, req) {
229
243
  testConnectionPermission(conid, req);
230
244
  const opened = await this.ensureOpened(conid);
245
+ if (!opened) {
246
+ return null;
247
+ }
231
248
  const res = await this.sendRequest(opened, { msgtype, ...args });
232
249
  if (res.errorMessage) {
233
250
  console.error(res.errorMessage);
@@ -249,6 +266,9 @@ module.exports = {
249
266
  async summaryCommand({ conid, command, row }, req) {
250
267
  testConnectionPermission(conid, req);
251
268
  const opened = await this.ensureOpened(conid);
269
+ if (!opened) {
270
+ return null;
271
+ }
252
272
  if (opened.connection.isReadOnly) return false;
253
273
  return this.loadDataCore('summaryCommand', { conid, command, row });
254
274
  },
@@ -12,15 +12,32 @@ const {
12
12
  storageReadConfig,
13
13
  storageWriteConfig,
14
14
  getStorageConnectionError,
15
+ storageSaveRelationDiff,
16
+ selectStorageIdentity,
15
17
  } = require('./storageDb');
16
18
  const { hasPermission } = require('../utility/hasPermission');
17
19
  const { changeSetToSql, removeSchemaFromChangeSet } = require('dbgate-datalib');
18
20
  const storageModel = require('../storageModel');
19
21
  const { dumpSqlCommand } = require('dbgate-sqltree');
20
- const { runCommandOnDriver, getLogger, runQueryFmt } = require('dbgate-tools');
22
+ const {
23
+ runCommandOnDriver,
24
+ getLogger,
25
+ runQueryFmt,
26
+ getPredefinedPermissions,
27
+ runQueryOnDriver,
28
+ } = require('dbgate-tools');
21
29
  const socket = require('../utility/socket');
22
30
  const { obtainRefreshedLicense } = require('../utility/authProxy');
23
31
  const { datadir } = require('../utility/directories');
32
+ const {
33
+ loadEncryptionKeyFromExternal,
34
+ encryptUser,
35
+ encryptConnection,
36
+ encryptPasswordString,
37
+ } = require('../utility/crypting');
38
+ const crypto = require('crypto');
39
+ const dataReplicator = require('../shell/dataReplicator');
40
+ const storageReplicatorItems = require('../utility/storageReplicatorItems');
24
41
 
25
42
  const logger = getLogger('storage');
26
43
 
@@ -31,7 +48,6 @@ function mapConnection(connnection) {
31
48
  };
32
49
  }
33
50
 
34
-
35
51
  let refreshLicenseStarted = false;
36
52
 
37
53
  module.exports = {
@@ -48,6 +64,22 @@ module.exports = {
48
64
  }
49
65
 
50
66
  setAuthProviders(providers, providers[defIndex]);
67
+
68
+ const keyResult = await storageSelectFmt(
69
+ "select ~value from ~config where ~group = 'admin' and ~key = 'encryptionKey'"
70
+ );
71
+ const [conn, driver] = await getStorageConnection();
72
+
73
+ await loadEncryptionKeyFromExternal(keyResult[0]?.value, async key => {
74
+ await runQueryFmt(
75
+ driver,
76
+ conn,
77
+ 'insert into ~config (~group, ~key, ~value) values (%v, %v, %v)',
78
+ 'admin',
79
+ 'encryptionKey',
80
+ key
81
+ );
82
+ });
51
83
  },
52
84
 
53
85
  async startRefreshLicense() {
@@ -135,7 +167,7 @@ module.exports = {
135
167
  displayName: 'Internal storage',
136
168
  defaultDatabase: process.env.STORAGE_DATABASE,
137
169
  singleDatabase: true,
138
- ...await getDbConnectionParams(),
170
+ ...(await getDbConnectionParams()),
139
171
  };
140
172
  }
141
173
 
@@ -183,8 +215,8 @@ module.exports = {
183
215
  return null;
184
216
  }
185
217
 
186
- await runQueryFmt(driver, conn, 'delete from auth_methods_config');
187
- await runQueryFmt(driver, conn, 'delete from auth_methods where id > 0');
218
+ await runQueryFmt(driver, conn, 'delete from ~auth_methods_config');
219
+ await runQueryFmt(driver, conn, 'delete from ~auth_methods where ~id > 0');
188
220
 
189
221
  let id = 1;
190
222
  for (const method of authMethods) {
@@ -192,7 +224,7 @@ module.exports = {
192
224
  await runQueryFmt(
193
225
  driver,
194
226
  conn,
195
- 'update auth_methods set name=%v, is_disabled=%v, is_default = %v, is_collapsed = %v where id = %v',
227
+ 'update ~auth_methods set ~name=%v, ~is_disabled=%v, ~is_default = %v, ~is_collapsed = %v where ~id = %v',
196
228
  method.name,
197
229
  method.isDisabled,
198
230
  method.isDefault,
@@ -228,7 +260,7 @@ module.exports = {
228
260
  await runQueryFmt(
229
261
  driver,
230
262
  conn,
231
- 'insert into auth_methods_config (%i, %i, %i) values (%v, %v, %v)',
263
+ 'insert into ~auth_methods_config (%i, %i, %i) values (%v, %v, %v)',
232
264
  'auth_method_id',
233
265
  'key',
234
266
  'value',
@@ -400,7 +432,7 @@ module.exports = {
400
432
  driver,
401
433
  conn,
402
434
  "insert into ~config (~group, ~key, ~value) values ('admin', 'adminPassword', %v)",
403
- newPassword
435
+ encryptPasswordString(newPassword)
404
436
  );
405
437
 
406
438
  return { status: 'ok' };
@@ -409,4 +441,305 @@ module.exports = {
409
441
  getStorageConnectionError() {
410
442
  return getStorageConnectionError();
411
443
  },
444
+
445
+ getUserList_meta: true,
446
+ async getUserList() {
447
+ const resp = await storageSelectFmt(`select ~users.~id,~users.~login,~users.~password,~users.~email from ~users`);
448
+ const usedRoles = await storageSelectFmt(`select ~roles.~name, ~user_roles.~user_id from
449
+ ~user_roles inner join ~roles ON ~user_roles.~role_id = ~roles.~id`);
450
+ const usedPermissions = await storageSelectFmt(`select * from ~user_permissions`);
451
+ return resp.map(x => ({
452
+ ...x,
453
+ password: x.password?.startsWith('crypt:') ? 'crypted' : x.password ? 'plain' : 'no',
454
+ usedRoles: usedRoles.filter(y => y.user_id == x.id).map(y => y.name),
455
+ usedPermissions: usedPermissions.filter(y => y.user_id == x.id).map(y => y.permission),
456
+ }));
457
+ },
458
+
459
+ getUserDetail_meta: true,
460
+ async getUserDetail({ id }) {
461
+ const resp =
462
+ id == 'new'
463
+ ? {}
464
+ : await storageSelectFmt(
465
+ `select ~users.~id,~users.~login,~users.password, ~users.~email from ~users where ~users.~id = %v`,
466
+ id
467
+ );
468
+
469
+ const rolePermissions = id == 'new' ? [] : await storageReadUserRolePermissions(id);
470
+ const basePermissions = [...getPredefinedPermissions('logged-user'), ...rolePermissions];
471
+ const permissions =
472
+ id == 'new'
473
+ ? []
474
+ : (await storageSelectFmt('select * from ~user_permissions where ~user_id = %v', id)).map(x => x.permission);
475
+ const allRoles = await storageSelectFmt('select * from ~roles');
476
+ const usedRoles =
477
+ id == 'new'
478
+ ? []
479
+ : (
480
+ await storageSelectFmt(`select ~user_roles.~role_id from ~user_roles where ~user_roles.~user_id = %v`, id)
481
+ ).map(x => x.role_id);
482
+ const allConnections = await storageSelectFmt('select * from ~connections');
483
+ const usedConnections =
484
+ id == 'new'
485
+ ? []
486
+ : (await storageSelectFmt('select ~connection_id from ~user_connections where ~user_id = %v', id)).map(
487
+ x => x.connection_id
488
+ );
489
+
490
+ return {
491
+ ...resp[0],
492
+ basePermissions,
493
+ permissions,
494
+ allRoles,
495
+ usedRoles,
496
+ allConnections,
497
+ usedConnections,
498
+ encryptPassword: !!(resp[0]?.password?.startsWith('crypt:') || id == 'new'),
499
+ };
500
+ },
501
+
502
+ saveUserDetail_meta: true,
503
+ async saveUserDetail(user) {
504
+ const [conn, driver] = await getStorageConnection();
505
+
506
+ const { login, password, email, usedRoles, usedConnections, permissions } = encryptUser(user);
507
+ let id = user.id;
508
+
509
+ if (id == null) {
510
+ await runQueryFmt(
511
+ driver,
512
+ conn,
513
+ 'insert into ~users (~login, ~password, ~email) values (%v, %v, %v)',
514
+ login,
515
+ password,
516
+ email
517
+ );
518
+ id = await selectStorageIdentity('users');
519
+ } else {
520
+ await runQueryFmt(
521
+ driver,
522
+ conn,
523
+ 'update ~users set ~login=%v, ~password=%v, ~email=%v where ~id = %v',
524
+ login,
525
+ password,
526
+ email,
527
+ id
528
+ );
529
+ }
530
+
531
+ await storageSaveRelationDiff('user_permissions', 'user_id', 'permission', id, permissions);
532
+ await storageSaveRelationDiff('user_roles', 'user_id', 'role_id', id, usedRoles);
533
+ await storageSaveRelationDiff('user_connections', 'user_id', 'connection_id', id, usedConnections);
534
+
535
+ return true;
536
+ },
537
+
538
+ deleteUser_meta: true,
539
+ async deleteUser({ id }) {
540
+ const [conn, driver] = await getStorageConnection();
541
+
542
+ await runQueryFmt(driver, conn, 'delete from ~users where ~id = %v', id);
543
+
544
+ return true;
545
+ },
546
+
547
+ getConnectionList_meta: true,
548
+ async getConnectionList() {
549
+ const resp = await storageSelectFmt(
550
+ `select ~connections.~id,~connections.~engine,~connections.~displayName,~connections.~server,~connections.~user from ~connections`
551
+ );
552
+ return resp;
553
+ },
554
+
555
+ getConnectionDetail_meta: true,
556
+ async getConnectionDetail({ id }) {
557
+ if (id == 'new') {
558
+ return {
559
+ conid: crypto.randomUUID(),
560
+ };
561
+ }
562
+
563
+ const resp = await storageSelectFmt(`select * from ~connections where ~id = %v`, id);
564
+ return resp[0];
565
+ },
566
+
567
+ saveConnectionDetail_meta: true,
568
+ async saveConnectionDetail(savedConnection) {
569
+ const [conn, driver] = await getStorageConnection();
570
+
571
+ const connection = encryptConnection(savedConnection);
572
+
573
+ const tableConnections = storageModel.tables.find(x => x.pureName == 'connections');
574
+ const id = connection.id;
575
+
576
+ const usedColumns = _.difference(
577
+ _.intersection(
578
+ tableConnections.columns.map(x => x.columnName),
579
+ Object.keys(connection)
580
+ ),
581
+ ['id']
582
+ );
583
+
584
+ if (id) {
585
+ await runQueryOnDriver(conn, driver, dmp => {
586
+ dmp.put(`update ~connections set`);
587
+ dmp.putCollection(',', usedColumns, col => {
588
+ dmp.put(`%i = %v`, col, connection[col]);
589
+ });
590
+ dmp.put(` where ~id = %v`, id);
591
+ });
592
+ } else {
593
+ await runQueryFmt(
594
+ driver,
595
+ conn,
596
+ `insert into ~connections (%,i) values (%,v)`,
597
+ usedColumns,
598
+ usedColumns.map(x => connection[x])
599
+ );
600
+ }
601
+
602
+ socket.emitChanged('connection-list-changed');
603
+
604
+ return true;
605
+ },
606
+
607
+ deleteConnection_meta: true,
608
+ async deleteConnection({ id }) {
609
+ const [conn, driver] = await getStorageConnection();
610
+ if (!conn) {
611
+ return null;
612
+ }
613
+
614
+ await runQueryFmt(driver, conn, 'delete from ~connections where ~id = %v', id);
615
+
616
+ socket.emitChanged('connection-list-changed');
617
+
618
+ return true;
619
+ },
620
+
621
+ getRoleList_meta: true,
622
+ async getRoleList() {
623
+ const resp = await storageSelectFmt(`select ~roles.~id,~roles.~name from ~roles`);
624
+ const usedPermissions = await storageSelectFmt(`select * from ~role_permissions`);
625
+ return resp.map(x => ({
626
+ ...x,
627
+ usedPermissions: usedPermissions.filter(y => y.role_id == x.id).map(y => y.permission),
628
+ }));
629
+ },
630
+
631
+ getRoleDetail_meta: true,
632
+ async getRoleDetail({ id }) {
633
+ const resp =
634
+ id == 'new' ? {} : await storageSelectFmt(`select ~roles.~id,~roles.~name from ~roles where ~roles.~id = %v`, id);
635
+
636
+ const basePermissions = getPredefinedPermissions(id < 0 && resp[0]?.name ? resp[0]?.name : 'logged-user');
637
+ const permissions =
638
+ id == 'new'
639
+ ? []
640
+ : (await storageSelectFmt('select * from ~role_permissions where ~role_id = %v', id)).map(x => x.permission);
641
+ const allUsers = await storageSelectFmt('select * from ~users');
642
+ const usedUsers =
643
+ id == 'new'
644
+ ? []
645
+ : (
646
+ await storageSelectFmt(`select ~user_roles.~user_id from ~user_roles where ~user_roles.~role_id = %v`, id)
647
+ ).map(x => x.user_id);
648
+ const allConnections = await storageSelectFmt('select * from ~connections');
649
+ const usedConnections =
650
+ id == 'new'
651
+ ? []
652
+ : (await storageSelectFmt('select ~connection_id from ~role_connections where ~role_id = %v', id)).map(
653
+ x => x.connection_id
654
+ );
655
+
656
+ return {
657
+ ...resp[0],
658
+ basePermissions,
659
+ permissions,
660
+ allUsers,
661
+ usedUsers,
662
+ allConnections,
663
+ usedConnections,
664
+ };
665
+ },
666
+
667
+ deleteRole_meta: true,
668
+ async deleteRole({ id }) {
669
+ const [conn, driver] = await getStorageConnection();
670
+ if (!conn) {
671
+ return null;
672
+ }
673
+
674
+ await runQueryFmt(driver, conn, 'delete from ~roles where ~id = %v', id);
675
+
676
+ return true;
677
+ },
678
+
679
+ saveRoleDetail_meta: true,
680
+ async saveRoleDetail(role) {
681
+ const [conn, driver] = await getStorageConnection();
682
+
683
+ const { name, usedConnections, usedUsers, permissions } = encryptUser(role);
684
+ let id = role.id;
685
+
686
+ if (id == null) {
687
+ await runQueryFmt(driver, conn, 'insert into ~roles (~name) values (%v)', name);
688
+ id = await selectStorageIdentity('roles');
689
+ } else {
690
+ if (id > 0) {
691
+ await runQueryFmt(driver, conn, 'update ~roles set ~name=%v where ~id = %v', name, id);
692
+ }
693
+ }
694
+
695
+ await storageSaveRelationDiff('role_permissions', 'role_id', 'permission', id, permissions);
696
+ await storageSaveRelationDiff('user_roles', 'role_id', 'user_id', id, usedUsers);
697
+ await storageSaveRelationDiff('role_connections', 'role_id', 'connection_id', id, usedConnections);
698
+
699
+ return true;
700
+ },
701
+
702
+ async getExportedDatabase() {
703
+ const connections = await storageSelectFmt(`select * from ~connections`);
704
+ const user_permissions = await storageSelectFmt(`select * from ~user_permissions`);
705
+ const users = await storageSelectFmt(`select * from ~users`);
706
+ const auth_methods = await storageSelectFmt(`select * from ~auth_methods`);
707
+ const role_connections = await storageSelectFmt(`select * from ~role_connections`);
708
+ const user_connections = await storageSelectFmt(`select * from ~user_connections`);
709
+ const user_roles = await storageSelectFmt(`select * from ~user_roles`);
710
+ const config = await storageSelectFmt(`select * from ~config`);
711
+ const auth_methods_config = await storageSelectFmt(`select * from ~auth_methods_config`);
712
+ const role_permissions = await storageSelectFmt(`select * from ~role_permissions`);
713
+ const roles = await storageSelectFmt(`select * from ~roles`);
714
+
715
+ return {
716
+ connections,
717
+ user_permissions,
718
+ users,
719
+ auth_methods,
720
+ role_connections,
721
+ user_connections,
722
+ user_roles,
723
+ config,
724
+ auth_methods_config,
725
+ role_permissions,
726
+ roles,
727
+ };
728
+ },
729
+
730
+ async replicateImportedDatabase(db) {
731
+ const [conn, driver] = await getStorageConnection();
732
+ // @ts-ignore
733
+ await dataReplicator({
734
+ systemConnection: conn,
735
+ driver,
736
+ items: storageReplicatorItems
737
+ .map(item => ({
738
+ ...item,
739
+ jsonArray: db[item.name],
740
+ }))
741
+ .filter(x => x.jsonArray),
742
+ });
743
+ socket.emitChanged('connection-list-changed');
744
+ },
412
745
  };