dbgate-api 4.7.3 → 4.7.4-alpha.12

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/.env CHANGED
@@ -1 +1,14 @@
1
1
  DEVMODE=1
2
+ # PERMISSIONS=~widgets/app,~widgets/plugins
3
+ # DISABLE_SHELL=1
4
+ # HIDE_APP_EDITOR=1
5
+
6
+
7
+ DEVWEB=1
8
+ LOGINS=admin,test
9
+
10
+ LOGIN_PASSWORD_admin=admin
11
+ LOGIN_PERMISSIONS_admin=*
12
+
13
+ LOGIN_PASSWORD_test=test
14
+ LOGIN_PERMISSIONS_test=~*, widgets/database
package/env/singledb/.env CHANGED
@@ -8,6 +8,8 @@ USER_mysql=root
8
8
  PASSWORD_mysql=test
9
9
  PORT_mysql=3307
10
10
  ENGINE_mysql=mysql@dbgate-plugin-mysql
11
+ DBCONFIG_mysql=[{"name":"Chinook","connectionColor":"cyan"}]
12
+
11
13
 
12
14
  SINGLE_CONNECTION=mysql
13
15
  SINGLE_DATABASE=Chinook
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dbgate-api",
3
3
  "main": "src/index.js",
4
- "version": "4.7.3",
4
+ "version": "4.7.4-alpha.12",
5
5
  "homepage": "https://dbgate.org/",
6
6
  "repository": {
7
7
  "type": "git",
@@ -25,9 +25,9 @@
25
25
  "compare-versions": "^3.6.0",
26
26
  "cors": "^2.8.5",
27
27
  "cross-env": "^6.0.3",
28
- "dbgate-query-splitter": "^4.7.3",
29
- "dbgate-sqltree": "^4.7.3",
30
- "dbgate-tools": "^4.7.3",
28
+ "dbgate-query-splitter": "^4.7.4-alpha.12",
29
+ "dbgate-sqltree": "^4.7.4-alpha.12",
30
+ "dbgate-tools": "^4.7.4-alpha.12",
31
31
  "diff": "^5.0.0",
32
32
  "diff2html": "^3.4.13",
33
33
  "eslint": "^6.8.0",
@@ -63,7 +63,7 @@
63
63
  "devDependencies": {
64
64
  "@types/fs-extra": "^9.0.11",
65
65
  "@types/lodash": "^4.14.149",
66
- "dbgate-types": "^4.7.3",
66
+ "dbgate-types": "^4.7.4-alpha.12",
67
67
  "env-cmd": "^10.1.0",
68
68
  "node-loader": "^1.0.2",
69
69
  "nodemon": "^2.0.2",
@@ -3,7 +3,7 @@ const os = require('os');
3
3
  const path = require('path');
4
4
  const axios = require('axios');
5
5
  const { datadir } = require('../utility/directories');
6
- const hasPermission = require('../utility/hasPermission');
6
+ const { hasPermission, getLogins } = require('../utility/hasPermission');
7
7
  const socket = require('../utility/socket');
8
8
  const _ = require('lodash');
9
9
  const AsyncLock = require('async-lock');
@@ -26,17 +26,31 @@ module.exports = {
26
26
  // },
27
27
 
28
28
  get_meta: true,
29
- async get() {
30
- const permissions = process.env.PERMISSIONS ? process.env.PERMISSIONS.split(',') : null;
29
+ async get(_params, req) {
30
+ const logins = getLogins();
31
+ const login = logins ? logins.find(x => x.login == (req.auth && req.auth.user)) : null;
32
+ const permissions = login ? login.permissions : null;
31
33
 
32
34
  return {
33
35
  runAsPortal: !!connections.portalConnections,
34
36
  singleDatabase: connections.singleDatabase,
37
+ // hideAppEditor: !!process.env.HIDE_APP_EDITOR,
38
+ allowShellConnection: platformInfo.allowShellConnection,
39
+ allowShellScripting: platformInfo.allowShellConnection,
35
40
  permissions,
41
+ login,
36
42
  ...currentVersion,
37
43
  };
38
44
  },
39
45
 
46
+ logout_meta: {
47
+ method: 'get',
48
+ raw: true,
49
+ },
50
+ logout(req, res) {
51
+ res.status(401).send('Logged out<br><a href="../..">Back to DbGate</a>');
52
+ },
53
+
40
54
  platformInfo_meta: true,
41
55
  async platformInfo() {
42
56
  return platformInfo;
@@ -64,8 +78,8 @@ module.exports = {
64
78
  },
65
79
 
66
80
  updateSettings_meta: true,
67
- async updateSettings(values) {
68
- if (!hasPermission(`settings/change`)) return false;
81
+ async updateSettings(values, req) {
82
+ if (!hasPermission(`settings/change`, req)) return false;
69
83
 
70
84
  const res = await lock.acquire('update', async () => {
71
85
  const currentValue = await this.getSettings();
@@ -5,12 +5,14 @@ const fs = require('fs-extra');
5
5
 
6
6
  const { datadir, filesdir } = require('../utility/directories');
7
7
  const socket = require('../utility/socket');
8
- const { encryptConnection } = require('../utility/crypting');
8
+ const { encryptConnection, maskConnection } = require('../utility/crypting');
9
9
  const { handleProcessCommunication } = require('../utility/processComm');
10
10
  const { pickSafeConnectionInfo } = require('../utility/crypting');
11
11
  const JsonLinesDatabase = require('../utility/JsonLinesDatabase');
12
12
 
13
13
  const processArgs = require('../utility/processArgs');
14
+ const { safeJsonParse } = require('dbgate-tools');
15
+ const platformInfo = require('../utility/platformInfo');
14
16
 
15
17
  function getNamedArgs() {
16
18
  const res = {};
@@ -55,6 +57,8 @@ function getPortalCollections() {
55
57
  (process.env[`FILE_${id}`] ? getDatabaseFileLabel(process.env[`FILE_${id}`]) : null),
56
58
  singleDatabase: !!process.env[`DATABASE_${id}`] || !!process.env[`FILE_${id}`],
57
59
  displayName: process.env[`LABEL_${id}`],
60
+ isReadOnly: process.env[`READONLY_${id}`],
61
+ databases: process.env[`DBCONFIG_${id}`] ? safeJsonParse(process.env[`DBCONFIG_${id}`]) : null,
58
62
 
59
63
  // SSH tunnel
60
64
  useSshTunnel: process.env[`USE_SSH_${id}`],
@@ -162,7 +166,9 @@ module.exports = {
162
166
 
163
167
  list_meta: true,
164
168
  async list() {
165
- return portalConnections || this.datastore.find();
169
+ return portalConnections && !platformInfo.allowShellConnection
170
+ ? portalConnections.map(maskConnection)
171
+ : this.datastore.find();
166
172
  },
167
173
 
168
174
  test_meta: true,
@@ -199,6 +205,9 @@ module.exports = {
199
205
  }
200
206
  socket.emitChanged('connection-list-changed');
201
207
  socket.emitChanged('used-apps-changed');
208
+ if (this._closeAll) {
209
+ this._closeAll(connection._id);
210
+ }
202
211
  // for (const db of connection.databases || []) {
203
212
  // socket.emitChanged(`db-apps-changed-${connection._id}-${db.name}`);
204
213
  // }
@@ -238,13 +247,21 @@ module.exports = {
238
247
  return res;
239
248
  },
240
249
 
241
- get_meta: true,
242
- async get({ conid }) {
243
- if (portalConnections) return portalConnections.find(x => x._id == conid) || null;
250
+ async getCore({ conid, mask = false }) {
251
+ if (!conid) return null;
252
+ if (portalConnections) {
253
+ const res = portalConnections.find(x => x._id == conid) || null;
254
+ return mask && !platformInfo.allowShellConnection ? maskConnection(res) : res;
255
+ }
244
256
  const res = await this.datastore.get(conid);
245
257
  return res || null;
246
258
  },
247
259
 
260
+ get_meta: true,
261
+ async get({ conid }) {
262
+ return this.getCore({ conid, mask: true });
263
+ },
264
+
248
265
  newSqliteDatabase_meta: true,
249
266
  async newSqliteDatabase({ file }) {
250
267
  const sqliteDir = path.join(filesdir(), 'sqlite');
@@ -33,6 +33,10 @@ module.exports = {
33
33
  closed: {},
34
34
  requests: {},
35
35
 
36
+ async _init() {
37
+ connections._closeAll = conid => this.closeAll(conid);
38
+ },
39
+
36
40
  handle_structure(conid, database, { structure }) {
37
41
  const existing = this.opened.find(x => x.conid == conid && x.database == database);
38
42
  if (!existing) return;
@@ -75,7 +79,7 @@ module.exports = {
75
79
  async ensureOpened(conid, database) {
76
80
  const existing = this.opened.find(x => x.conid == conid && x.database == database);
77
81
  if (existing) return existing;
78
- const connection = await connections.get({ conid });
82
+ const connection = await connections.getCore({ conid });
79
83
  const subprocess = fork(global['API_PACKAGE'] || process.argv[1], [
80
84
  '--is-forked-api',
81
85
  '--start-process',
@@ -136,6 +140,13 @@ module.exports = {
136
140
  return res;
137
141
  },
138
142
 
143
+ sqlSelect_meta: true,
144
+ async sqlSelect({ conid, database, select }) {
145
+ const opened = await this.ensureOpened(conid, database);
146
+ const res = await this.sendRequest(opened, { msgtype: 'sqlSelect', select });
147
+ return res;
148
+ },
149
+
139
150
  runScript_meta: true,
140
151
  async runScript({ conid, database, sql }) {
141
152
  console.log(`Processing script, conid=${conid}, database=${database}, sql=${sql}`);
@@ -148,14 +159,64 @@ module.exports = {
148
159
  async collectionData({ conid, database, options }) {
149
160
  const opened = await this.ensureOpened(conid, database);
150
161
  const res = await this.sendRequest(opened, { msgtype: 'collectionData', options });
151
- return res.result;
162
+ return res.result || null;
163
+ },
164
+
165
+ async loadDataCore(msgtype, { conid, database, ...args }) {
166
+ const opened = await this.ensureOpened(conid, database);
167
+ const res = await this.sendRequest(opened, { msgtype, ...args });
168
+ if (res.errorMessage) {
169
+ console.error(res.errorMessage);
170
+
171
+ return {
172
+ errorMessage: res.errorMessage,
173
+ };
174
+ }
175
+ return res.result || null;
176
+ },
177
+
178
+ loadKeys_meta: true,
179
+ async loadKeys({ conid, database, root }) {
180
+ return this.loadDataCore('loadKeys', { conid, database, root });
181
+ },
182
+
183
+ loadKeyInfo_meta: true,
184
+ async loadKeyInfo({ conid, database, key }) {
185
+ return this.loadDataCore('loadKeyInfo', { conid, database, key });
186
+ },
187
+
188
+ loadKeyTableRange_meta: true,
189
+ async loadKeyTableRange({ conid, database, key, cursor, count }) {
190
+ return this.loadDataCore('loadKeyTableRange', { conid, database, key, cursor, count });
191
+ },
192
+
193
+ loadFieldValues_meta: true,
194
+ async loadFieldValues({ conid, database, schemaName, pureName, field, search }) {
195
+ return this.loadDataCore('loadFieldValues', { conid, database, schemaName, pureName, field, search });
196
+ },
197
+
198
+ callMethod_meta: true,
199
+ async callMethod({ conid, database, method, args }) {
200
+ return this.loadDataCore('callMethod', { conid, database, method, args });
201
+
202
+ // const opened = await this.ensureOpened(conid, database);
203
+ // const res = await this.sendRequest(opened, { msgtype: 'callMethod', method, args });
204
+ // if (res.errorMessage) {
205
+ // console.error(res.errorMessage);
206
+ // }
207
+ // return res.result || null;
152
208
  },
153
209
 
154
210
  updateCollection_meta: true,
155
211
  async updateCollection({ conid, database, changeSet }) {
156
212
  const opened = await this.ensureOpened(conid, database);
157
213
  const res = await this.sendRequest(opened, { msgtype: 'updateCollection', changeSet });
158
- return res.result;
214
+ if (res.errorMessage) {
215
+ return {
216
+ errorMessage: res.errorMessage,
217
+ };
218
+ }
219
+ return res.result || null;
159
220
  },
160
221
 
161
222
  status_meta: true,
@@ -228,6 +289,12 @@ module.exports = {
228
289
  }
229
290
  },
230
291
 
292
+ closeAll(conid, kill = true) {
293
+ for (const existing of this.opened.filter(x => x.conid == conid)) {
294
+ this.close(conid, existing.database, kill);
295
+ }
296
+ },
297
+
231
298
  disconnect_meta: true,
232
299
  async disconnect({ conid, database }) {
233
300
  await this.close(conid, database, true);
@@ -325,8 +392,8 @@ module.exports = {
325
392
  const targetDb = generateDbPairingId(
326
393
  extendDatabaseInfo(await this.structure({ conid: targetConid, database: targetDatabase }))
327
394
  );
328
- // const sourceConnection = await connections.get({conid:sourceConid})
329
- const connection = await connections.get({ conid: targetConid });
395
+ // const sourceConnection = await connections.getCore({conid:sourceConid})
396
+ const connection = await connections.getCore({ conid: targetConid });
330
397
  const driver = requireEngineDriver(connection);
331
398
  const targetDbPaired = matchPairedObjects(sourceDb, targetDb, dbDiffOptions);
332
399
  const diffRows = computeDbDiffRows(sourceDb, targetDbPaired, dbDiffOptions, driver);
@@ -3,7 +3,7 @@ const fs = require('fs-extra');
3
3
  const path = require('path');
4
4
  const { filesdir, archivedir, resolveArchiveFolder, uploadsdir, appdir } = require('../utility/directories');
5
5
  const getChartExport = require('../utility/getChartExport');
6
- const hasPermission = require('../utility/hasPermission');
6
+ const { hasPermission } = require('../utility/hasPermission');
7
7
  const socket = require('../utility/socket');
8
8
  const scheduler = require('./scheduler');
9
9
  const getDiagramExport = require('../utility/getDiagramExport');
@@ -23,8 +23,8 @@ function deserialize(format, text) {
23
23
 
24
24
  module.exports = {
25
25
  list_meta: true,
26
- async list({ folder }) {
27
- if (!hasPermission(`files/${folder}/read`)) return [];
26
+ async list({ folder }, req) {
27
+ if (!hasPermission(`files/${folder}/read`, req)) return [];
28
28
  const dir = path.join(filesdir(), folder);
29
29
  if (!(await fs.exists(dir))) return [];
30
30
  const files = (await fs.readdir(dir)).map(file => ({ folder, file }));
@@ -32,11 +32,11 @@ module.exports = {
32
32
  },
33
33
 
34
34
  listAll_meta: true,
35
- async listAll() {
35
+ async listAll(_params, req) {
36
36
  const folders = await fs.readdir(filesdir());
37
37
  const res = [];
38
38
  for (const folder of folders) {
39
- if (!hasPermission(`files/${folder}/read`)) continue;
39
+ if (!hasPermission(`files/${folder}/read`, req)) continue;
40
40
  const dir = path.join(filesdir(), folder);
41
41
  const files = (await fs.readdir(dir)).map(file => ({ folder, file }));
42
42
  res.push(...files);
@@ -45,31 +45,34 @@ module.exports = {
45
45
  },
46
46
 
47
47
  delete_meta: true,
48
- async delete({ folder, file }) {
49
- if (!hasPermission(`files/${folder}/write`)) return;
48
+ async delete({ folder, file }, req) {
49
+ if (!hasPermission(`files/${folder}/write`, req)) return false;
50
50
  await fs.unlink(path.join(filesdir(), folder, file));
51
51
  socket.emitChanged(`files-changed-${folder}`);
52
52
  socket.emitChanged(`all-files-changed`);
53
+ return true;
53
54
  },
54
55
 
55
56
  rename_meta: true,
56
- async rename({ folder, file, newFile }) {
57
- if (!hasPermission(`files/${folder}/write`)) return;
57
+ async rename({ folder, file, newFile }, req) {
58
+ if (!hasPermission(`files/${folder}/write`, req)) return false;
58
59
  await fs.rename(path.join(filesdir(), folder, file), path.join(filesdir(), folder, newFile));
59
60
  socket.emitChanged(`files-changed-${folder}`);
60
61
  socket.emitChanged(`all-files-changed`);
62
+ return true;
61
63
  },
62
64
 
63
65
  copy_meta: true,
64
- async copy({ folder, file, newFile }) {
65
- if (!hasPermission(`files/${folder}/write`)) return;
66
+ async copy({ folder, file, newFile }, req) {
67
+ if (!hasPermission(`files/${folder}/write`, req)) return false;
66
68
  await fs.copyFile(path.join(filesdir(), folder, file), path.join(filesdir(), folder, newFile));
67
69
  socket.emitChanged(`files-changed-${folder}`);
68
70
  socket.emitChanged(`all-files-changed`);
71
+ return true;
69
72
  },
70
73
 
71
74
  load_meta: true,
72
- async load({ folder, file, format }) {
75
+ async load({ folder, file, format }, req) {
73
76
  if (folder.startsWith('archive:')) {
74
77
  const text = await fs.readFile(path.join(resolveArchiveFolder(folder.substring('archive:'.length)), file), {
75
78
  encoding: 'utf-8',
@@ -81,20 +84,22 @@ module.exports = {
81
84
  });
82
85
  return deserialize(format, text);
83
86
  } else {
84
- if (!hasPermission(`files/${folder}/read`)) return null;
87
+ if (!hasPermission(`files/${folder}/read`, req)) return null;
85
88
  const text = await fs.readFile(path.join(filesdir(), folder, file), { encoding: 'utf-8' });
86
89
  return deserialize(format, text);
87
90
  }
88
91
  },
89
92
 
90
93
  save_meta: true,
91
- async save({ folder, file, data, format }) {
94
+ async save({ folder, file, data, format }, req) {
92
95
  if (folder.startsWith('archive:')) {
96
+ if (!hasPermission(`archive/write`, req)) return false;
93
97
  const dir = resolveArchiveFolder(folder.substring('archive:'.length));
94
98
  await fs.writeFile(path.join(dir, file), serialize(format, data));
95
99
  socket.emitChanged(`archive-files-changed-${folder.substring('archive:'.length)}`);
96
100
  return true;
97
101
  } else if (folder.startsWith('app:')) {
102
+ if (!hasPermission(`apps/write`, req)) return false;
98
103
  const app = folder.substring('app:'.length);
99
104
  await fs.writeFile(path.join(appdir(), app, file), serialize(format, data));
100
105
  socket.emitChanged(`app-files-changed-${app}`);
@@ -102,7 +107,7 @@ module.exports = {
102
107
  apps.emitChangedDbApp(folder);
103
108
  return true;
104
109
  } else {
105
- if (!hasPermission(`files/${folder}/write`)) return false;
110
+ if (!hasPermission(`files/${folder}/write`, req)) return false;
106
111
  const dir = path.join(filesdir(), folder);
107
112
  if (!(await fs.exists(dir))) {
108
113
  await fs.mkdir(dir);
@@ -123,8 +128,8 @@ module.exports = {
123
128
  },
124
129
 
125
130
  favorites_meta: true,
126
- async favorites() {
127
- if (!hasPermission(`files/favorites/read`)) return [];
131
+ async favorites(_params, req) {
132
+ if (!hasPermission(`files/favorites/read`, req)) return [];
128
133
  const dir = path.join(filesdir(), 'favorites');
129
134
  if (!(await fs.exists(dir))) return [];
130
135
  const files = await fs.readdir(dir);
@@ -111,18 +111,22 @@ module.exports = {
111
111
  getInfo_meta: true,
112
112
  async getInfo({ jslid }) {
113
113
  const file = getJslFileName(jslid);
114
- const firstLine = await readFirstLine(file);
115
- if (firstLine) {
116
- const parsed = JSON.parse(firstLine);
117
- if (parsed.__isStreamHeader) {
118
- return parsed;
114
+ try {
115
+ const firstLine = await readFirstLine(file);
116
+ if (firstLine) {
117
+ const parsed = JSON.parse(firstLine);
118
+ if (parsed.__isStreamHeader) {
119
+ return parsed;
120
+ }
121
+ return {
122
+ __isStreamHeader: true,
123
+ __isDynamicStructure: true,
124
+ };
119
125
  }
120
- return {
121
- __isStreamHeader: true,
122
- __isDynamicStructure: true,
123
- };
126
+ return null;
127
+ } catch (err) {
128
+ return null;
124
129
  }
125
- return null;
126
130
  },
127
131
 
128
132
  getRows_meta: true,
@@ -7,7 +7,7 @@ const socket = require('../utility/socket');
7
7
  const compareVersions = require('compare-versions');
8
8
  const requirePlugin = require('../shell/requirePlugin');
9
9
  const downloadPackage = require('../utility/downloadPackage');
10
- const hasPermission = require('../utility/hasPermission');
10
+ const { hasPermission } = require('../utility/hasPermission');
11
11
  const _ = require('lodash');
12
12
  const packagedPluginsContent = require('../packagedPluginsContent');
13
13
 
@@ -73,7 +73,7 @@ module.exports = {
73
73
  const res = [];
74
74
  for (const packageName of _.union(files1, files2)) {
75
75
  if (packageName == 'dist') continue;
76
- // if (!/^dbgate-plugin-.*$/.test(packageName)) continue;
76
+ if (!/^dbgate-plugin-.*$/.test(packageName)) continue;
77
77
  try {
78
78
  if (packagedContent && packagedContent[packageName]) {
79
79
  const manifest = {
@@ -115,8 +115,8 @@ module.exports = {
115
115
  // },
116
116
 
117
117
  install_meta: true,
118
- async install({ packageName }) {
119
- if (!hasPermission(`plugins/install`)) return;
118
+ async install({ packageName }, req) {
119
+ if (!hasPermission(`plugins/install`, req)) return;
120
120
  const dir = path.join(pluginsdir(), packageName);
121
121
  // @ts-ignore
122
122
  if (!(await fs.exists(dir))) {
@@ -128,8 +128,8 @@ module.exports = {
128
128
  },
129
129
 
130
130
  uninstall_meta: true,
131
- async uninstall({ packageName }) {
132
- if (!hasPermission(`plugins/install`)) return;
131
+ async uninstall({ packageName }, req) {
132
+ if (!hasPermission(`plugins/install`, req)) return;
133
133
  const dir = path.join(pluginsdir(), packageName);
134
134
  await fs.rmdir(dir, { recursive: true });
135
135
  socket.emitChanged(`installed-plugins-changed`);
@@ -138,8 +138,8 @@ module.exports = {
138
138
  },
139
139
 
140
140
  upgrade_meta: true,
141
- async upgrade({ packageName }) {
142
- if (!hasPermission(`plugins/install`)) return;
141
+ async upgrade({ packageName }, req) {
142
+ if (!hasPermission(`plugins/install`, req)) return;
143
143
  const dir = path.join(pluginsdir(), packageName);
144
144
  // @ts-ignore
145
145
  if (await fs.exists(dir)) {
@@ -6,9 +6,10 @@ const byline = require('byline');
6
6
  const socket = require('../utility/socket');
7
7
  const { fork } = require('child_process');
8
8
  const { rundir, uploadsdir, pluginsdir, getPluginBackendPath, packagedPluginList } = require('../utility/directories');
9
- const { extractShellApiPlugins, extractShellApiFunctionName } = require('dbgate-tools');
9
+ const { extractShellApiPlugins, extractShellApiFunctionName, jsonScriptToJavascript } = require('dbgate-tools');
10
10
  const { handleProcessCommunication } = require('../utility/processComm');
11
11
  const processArgs = require('../utility/processArgs');
12
+ const platformInfo = require('../utility/platformInfo');
12
13
 
13
14
  function extractPlugins(script) {
14
15
  const requireRegex = /\s*\/\/\s*@require\s+([^\s]+)\s*\n/g;
@@ -110,7 +111,7 @@ module.exports = {
110
111
  stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
111
112
  env: {
112
113
  ...process.env,
113
- DBGATE_API: global['API_PACKAGE'] || global['dbgateApiModulePath'] || process.argv[1],
114
+ DBGATE_API: global['API_PACKAGE'] || process.argv[1],
114
115
  ..._.fromPairs(pluginNames.map(name => [`PLUGIN_${_.camelCase(name)}`, getPluginBackendPath(name)])),
115
116
  },
116
117
  }
@@ -150,6 +151,16 @@ module.exports = {
150
151
  start_meta: true,
151
152
  async start({ script }) {
152
153
  const runid = uuidv1();
154
+
155
+ if (script.type == 'json') {
156
+ const js = jsonScriptToJavascript(script);
157
+ return this.startCore(runid, scriptTemplate(js, false));
158
+ }
159
+
160
+ if (!platformInfo.allowShellScripting) {
161
+ return { errorMessage: 'Shell scripting is not allowed' };
162
+ }
163
+
153
164
  return this.startCore(runid, scriptTemplate(script, false));
154
165
  },
155
166
 
@@ -3,7 +3,7 @@ const fs = require('fs-extra');
3
3
  const path = require('path');
4
4
  const cron = require('node-cron');
5
5
  const runners = require('./runners');
6
- const hasPermission = require('../utility/hasPermission');
6
+ const { hasPermission } = require('../utility/hasPermission');
7
7
 
8
8
  const scheduleRegex = /\s*\/\/\s*@schedule\s+([^\n]+)\n/;
9
9
 
@@ -26,8 +26,8 @@ module.exports = {
26
26
  this.tasks.push(task);
27
27
  },
28
28
 
29
- async reload() {
30
- if (!hasPermission('files/shell/read')) return;
29
+ async reload(_params, req) {
30
+ if (!hasPermission('files/shell/read', req)) return;
31
31
  const shellDir = path.join(filesdir(), 'shell');
32
32
  await this.unload();
33
33
  if (!(await fs.exists(shellDir))) return;
@@ -37,7 +37,7 @@ module.exports = {
37
37
  const res = await lock.acquire(conid, async () => {
38
38
  const existing = this.opened.find(x => x.conid == conid);
39
39
  if (existing) return existing;
40
- const connection = await connections.get({ conid });
40
+ const connection = await connections.getCore({ conid });
41
41
  const subprocess = fork(global['API_PACKAGE'] || process.argv[1], [
42
42
  '--is-forked-api',
43
43
  '--start-process',
@@ -4,8 +4,10 @@ const connections = require('./connections');
4
4
  const socket = require('../utility/socket');
5
5
  const { fork } = require('child_process');
6
6
  const jsldata = require('./jsldata');
7
+ const path = require('path');
7
8
  const { handleProcessCommunication } = require('../utility/processComm');
8
9
  const processArgs = require('../utility/processArgs');
10
+ const { appdir } = require('../utility/directories');
9
11
 
10
12
  module.exports = {
11
13
  /** @type {import('dbgate-types').OpenedSession[]} */
@@ -46,9 +48,18 @@ module.exports = {
46
48
  this.dispatchMessage(sesid, info);
47
49
  },
48
50
 
49
- handle_done(sesid) {
51
+ handle_done(sesid, props) {
50
52
  socket.emit(`session-done-${sesid}`);
51
- this.dispatchMessage(sesid, 'Query execution finished');
53
+ if (!props.skipFinishedMessage) {
54
+ this.dispatchMessage(sesid, 'Query execution finished');
55
+ }
56
+ const session = this.opened.find(x => x.sesid == sesid);
57
+ if (session.loadingReader_jslid) {
58
+ socket.emit(`session-jslid-done-${session.loadingReader_jslid}`);
59
+ }
60
+ if (session.killOnDone) {
61
+ this.kill({ sesid });
62
+ }
52
63
  },
53
64
 
54
65
  handle_recordset(sesid, props) {
@@ -60,12 +71,17 @@ module.exports = {
60
71
  jsldata.notifyChangedStats(stats);
61
72
  },
62
73
 
74
+ handle_initializeFile(sesid, props) {
75
+ const { jslid } = props;
76
+ socket.emit(`session-initialize-file-${jslid}`);
77
+ },
78
+
63
79
  handle_ping() {},
64
80
 
65
81
  create_meta: true,
66
82
  async create({ conid, database }) {
67
83
  const sesid = uuidv1();
68
- const connection = await connections.get({ conid });
84
+ const connection = await connections.getCore({ conid });
69
85
  const subprocess = fork(global['API_PACKAGE'] || process.argv[1], [
70
86
  '--is-forked-api',
71
87
  '--start-process',
@@ -105,6 +121,29 @@ module.exports = {
105
121
  return { state: 'ok' };
106
122
  },
107
123
 
124
+ executeReader_meta: true,
125
+ async executeReader({ conid, database, sql, queryName, appFolder }) {
126
+ const { sesid } = await this.create({ conid, database });
127
+ const session = this.opened.find(x => x.sesid == sesid);
128
+ session.killOnDone = true;
129
+ const jslid = uuidv1();
130
+ session.loadingReader_jslid = jslid;
131
+ const fileName = queryName && appFolder ? path.join(appdir(), appFolder, `${queryName}.query.sql`) : null;
132
+
133
+ session.subprocess.send({ msgtype: 'executeReader', sql, fileName, jslid });
134
+
135
+ return { jslid };
136
+ },
137
+
138
+ stopLoadingReader_meta: true,
139
+ async stopLoadingReader({ jslid }) {
140
+ const session = this.opened.find(x => x.loadingReader_jslid == jslid);
141
+ if (session) {
142
+ this.kill({ sesid: session.sesid });
143
+ }
144
+ return true;
145
+ },
146
+
108
147
  // cancel_meta: true,
109
148
  // async cancel({ sesid }) {
110
149
  // const session = this.opened.find((x) => x.sesid == sesid);
@@ -1,5 +1,5 @@
1
1
 
2
2
  module.exports = {
3
- version: '4.7.3',
4
- buildTime: '2022-03-14T19:11:28.854Z'
3
+ version: '4.7.4-alpha.12',
4
+ buildTime: '2022-03-24T08:15:55.138Z'
5
5
  };
package/src/index.js CHANGED
@@ -8,7 +8,7 @@ if (processArgs.startProcess) {
8
8
  const proc = require('./proc');
9
9
  const module = proc[processArgs.startProcess];
10
10
  module.start();
11
- } else if (!processArgs.checkParent && !global['API_PACKAGE'] && !global['dbgateApiModulePath']) {
11
+ } else if (!processArgs.checkParent && !global['API_PACKAGE']) {
12
12
  const main = require('./main');
13
13
 
14
14
  main.start();