@budibase/server 1.0.27-alpha.4 → 1.0.27-alpha.8
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/builder/assets/{index.431d69df.css → index.0dce895b.css} +1 -1
- package/builder/assets/{index.d849c3ee.js → index.d5347573.js} +155 -155
- package/builder/index.html +2 -2
- package/coverage/clover.xml +399 -349
- package/coverage/coverage-final.json +4 -4
- package/coverage/lcov-report/api/controllers/analytics.js.html +1 -1
- package/coverage/lcov-report/api/controllers/apikeys.js.html +1 -1
- package/coverage/lcov-report/api/controllers/application.js.html +1 -1
- package/coverage/lcov-report/api/controllers/auth.js.html +1 -1
- package/coverage/lcov-report/api/controllers/automation.js.html +1 -1
- package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
- package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
- package/coverage/lcov-report/api/controllers/component.js.html +1 -1
- package/coverage/lcov-report/api/controllers/datasource.js.html +1 -1
- package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
- package/coverage/lcov-report/api/controllers/hosting.js.html +1 -1
- package/coverage/lcov-report/api/controllers/index.html +1 -1
- package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
- package/coverage/lcov-report/api/controllers/layout.js.html +1 -1
- package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
- package/coverage/lcov-report/api/controllers/permission.js.html +1 -1
- package/coverage/lcov-report/api/controllers/query/index.html +19 -19
- package/coverage/lcov-report/api/controllers/query/index.js.html +73 -10
- package/coverage/lcov-report/api/controllers/query/validation.js.html +1 -1
- package/coverage/lcov-report/api/controllers/role.js.html +1 -1
- package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/external.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/index.html +11 -11
- package/coverage/lcov-report/api/controllers/row/index.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/internal.js.html +38 -11
- package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/utils.js.html +1 -1
- package/coverage/lcov-report/api/controllers/screen.js.html +1 -1
- package/coverage/lcov-report/api/controllers/script.js.html +1 -1
- package/coverage/lcov-report/api/controllers/table/external.js.html +1 -1
- package/coverage/lcov-report/api/controllers/table/index.html +1 -1
- package/coverage/lcov-report/api/controllers/table/index.js.html +1 -1
- package/coverage/lcov-report/api/controllers/table/internal.js.html +1 -1
- package/coverage/lcov-report/api/controllers/table/utils.js.html +1 -1
- package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
- package/coverage/lcov-report/api/controllers/user.js.html +1 -1
- package/coverage/lcov-report/api/controllers/view/exporters.js.html +1 -1
- package/coverage/lcov-report/api/controllers/view/index.html +1 -1
- package/coverage/lcov-report/api/controllers/view/index.js.html +1 -1
- package/coverage/lcov-report/api/controllers/view/utils.js.html +1 -1
- package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +1 -1
- package/coverage/lcov-report/api/controllers/webhook.js.html +1 -1
- package/coverage/lcov-report/api/index.html +1 -1
- package/coverage/lcov-report/api/index.js.html +1 -1
- package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
- package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
- package/coverage/lcov-report/api/routes/application.js.html +1 -1
- package/coverage/lcov-report/api/routes/auth.js.html +1 -1
- package/coverage/lcov-report/api/routes/automation.js.html +1 -1
- package/coverage/lcov-report/api/routes/backup.js.html +1 -1
- package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
- package/coverage/lcov-report/api/routes/component.js.html +1 -1
- package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
- package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
- package/coverage/lcov-report/api/routes/dev.js.html +1 -1
- package/coverage/lcov-report/api/routes/hosting.js.html +1 -1
- package/coverage/lcov-report/api/routes/index.html +1 -1
- package/coverage/lcov-report/api/routes/index.js.html +1 -1
- package/coverage/lcov-report/api/routes/integration.js.html +1 -1
- package/coverage/lcov-report/api/routes/layout.js.html +1 -1
- package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
- package/coverage/lcov-report/api/routes/permission.js.html +1 -1
- package/coverage/lcov-report/api/routes/query.js.html +1 -1
- package/coverage/lcov-report/api/routes/role.js.html +1 -1
- package/coverage/lcov-report/api/routes/routing.js.html +1 -1
- package/coverage/lcov-report/api/routes/row.js.html +1 -1
- package/coverage/lcov-report/api/routes/screen.js.html +1 -1
- package/coverage/lcov-report/api/routes/script.js.html +1 -1
- package/coverage/lcov-report/api/routes/static.js.html +1 -1
- package/coverage/lcov-report/api/routes/table.js.html +1 -1
- package/coverage/lcov-report/api/routes/templates.js.html +1 -1
- package/coverage/lcov-report/api/routes/user.js.html +1 -1
- package/coverage/lcov-report/api/routes/view.js.html +1 -1
- package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
- package/coverage/lcov-report/automations/actions.js.html +1 -1
- package/coverage/lcov-report/automations/automationUtils.js.html +1 -1
- package/coverage/lcov-report/automations/bullboard.js.html +1 -1
- package/coverage/lcov-report/automations/index.html +1 -1
- package/coverage/lcov-report/automations/index.js.html +1 -1
- package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
- package/coverage/lcov-report/automations/steps/createRow.js.html +1 -1
- package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
- package/coverage/lcov-report/automations/steps/deleteRow.js.html +1 -1
- package/coverage/lcov-report/automations/steps/discord.js.html +1 -1
- package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
- package/coverage/lcov-report/automations/steps/executeScript.js.html +1 -1
- package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
- package/coverage/lcov-report/automations/steps/index.html +1 -1
- package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
- package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +1 -1
- package/coverage/lcov-report/automations/steps/queryRows.js.html +1 -1
- package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
- package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
- package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
- package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
- package/coverage/lcov-report/automations/steps/utils.js.html +1 -1
- package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/app.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/cron.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/index.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +1 -1
- package/coverage/lcov-report/automations/triggers.js.html +1 -1
- package/coverage/lcov-report/automations/utils.js.html +1 -1
- package/coverage/lcov-report/constants/index.html +1 -1
- package/coverage/lcov-report/constants/index.js.html +1 -1
- package/coverage/lcov-report/constants/layouts.js.html +1 -1
- package/coverage/lcov-report/constants/screens.js.html +1 -1
- package/coverage/lcov-report/db/client.js.html +1 -1
- package/coverage/lcov-report/db/inMemoryView.js.html +1 -1
- package/coverage/lcov-report/db/index.html +1 -1
- package/coverage/lcov-report/db/index.js.html +1 -1
- package/coverage/lcov-report/db/linkedRows/LinkController.js.html +1 -1
- package/coverage/lcov-report/db/linkedRows/index.html +1 -1
- package/coverage/lcov-report/db/linkedRows/index.js.html +1 -1
- package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +1 -1
- package/coverage/lcov-report/db/newid.js.html +1 -1
- package/coverage/lcov-report/db/utils.js.html +1 -1
- package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
- package/coverage/lcov-report/events/index.html +1 -1
- package/coverage/lcov-report/events/index.js.html +1 -1
- package/coverage/lcov-report/events/utils.js.html +1 -1
- package/coverage/lcov-report/index.html +39 -39
- package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
- package/coverage/lcov-report/integrations/tests/index.html +1 -1
- package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
- package/coverage/lcov-report/middleware/authorized.js.html +1 -1
- package/coverage/lcov-report/middleware/builder.js.html +1 -1
- package/coverage/lcov-report/middleware/currentapp.js.html +1 -1
- package/coverage/lcov-report/middleware/index.html +1 -1
- package/coverage/lcov-report/middleware/joi-validator.js.html +1 -1
- package/coverage/lcov-report/middleware/resourceId.js.html +1 -1
- package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
- package/coverage/lcov-report/middleware/usageQuota.js.html +1 -1
- package/coverage/lcov-report/middleware/utils.js.html +1 -1
- package/coverage/lcov-report/threads/automation.js.html +1 -1
- package/coverage/lcov-report/threads/index.html +11 -11
- package/coverage/lcov-report/threads/index.js.html +1 -1
- package/coverage/lcov-report/threads/query.js.html +1 -1
- package/coverage/lcov-report/threads/utils.js.html +28 -25
- package/coverage/lcov-report/utilities/bcrypt.js.html +1 -1
- package/coverage/lcov-report/utilities/budibaseDir.js.html +1 -1
- package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
- package/coverage/lcov-report/utilities/csvParser.js.html +1 -1
- package/coverage/lcov-report/utilities/global.js.html +1 -1
- package/coverage/lcov-report/utilities/index.html +1 -1
- package/coverage/lcov-report/utilities/index.js.html +1 -1
- package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +1 -1
- package/coverage/lcov-report/utilities/queue/index.html +1 -1
- package/coverage/lcov-report/utilities/routing/index.html +1 -1
- package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
- package/coverage/lcov-report/utilities/rowProcessor/index.html +19 -19
- package/coverage/lcov-report/utilities/rowProcessor/index.js.html +199 -10
- package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +1 -1
- package/coverage/lcov-report/utilities/scriptRunner.js.html +1 -1
- package/coverage/lcov-report/utilities/security.js.html +1 -1
- package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
- package/coverage/lcov-report/utilities/users.js.html +1 -1
- package/coverage/lcov-report/utilities/workerRequests.js.html +1 -1
- package/coverage/lcov.info +668 -572
- package/dist/api/controllers/query/import/sources/base/index.js +2 -1
- package/dist/api/controllers/query/import/sources/curl.js +6 -4
- package/dist/api/controllers/query/import/sources/openapi2.js +8 -5
- package/dist/api/controllers/query/index.js +16 -0
- package/dist/api/controllers/row/internal.js +14 -6
- package/dist/integrations/base/sqlTable.js +1 -1
- package/dist/integrations/rest.js +1 -1
- package/dist/package.json +4 -4
- package/dist/threads/utils.js +2 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utilities/fileSystem/utilities.js +2 -1
- package/dist/utilities/rowProcessor/index.js +63 -0
- package/package.json +5 -5
- package/src/api/controllers/query/import/sources/base/index.ts +3 -1
- package/src/api/controllers/query/import/sources/curl.ts +7 -3
- package/src/api/controllers/query/import/sources/openapi2.ts +9 -5
- package/src/api/controllers/query/import/sources/tests/curl/curl.spec.js +2 -3
- package/src/api/controllers/query/import/sources/tests/openapi2/openapi2.spec.js +6 -7
- package/src/api/controllers/query/import/tests/index.spec.js +0 -6
- package/src/api/controllers/query/index.js +21 -0
- package/src/api/controllers/row/internal.js +14 -5
- package/src/integrations/base/sqlTable.ts +1 -1
- package/src/integrations/rest.ts +1 -1
- package/src/threads/utils.js +2 -1
- package/src/utilities/fileSystem/utilities.js +2 -0
- package/src/utilities/rowProcessor/index.js +63 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
const { ObjectStore, makeSureBucketExists, upload, streamUpload, retrieve, retrieveToTmp, deleteFolder, uploadDirectory, downloadTarball, } = require("@budibase/auth").objectStore;
|
|
2
|
+
const { ObjectStore, makeSureBucketExists, upload, deleteFiles, streamUpload, retrieve, retrieveToTmp, deleteFolder, uploadDirectory, downloadTarball, } = require("@budibase/auth").objectStore;
|
|
3
3
|
/***********************************
|
|
4
4
|
* NOTE *
|
|
5
5
|
* This file purely exists so that *
|
|
@@ -17,3 +17,4 @@ exports.retrieveToTmp = retrieveToTmp;
|
|
|
17
17
|
exports.deleteFolder = deleteFolder;
|
|
18
18
|
exports.uploadDirectory = uploadDirectory;
|
|
19
19
|
exports.downloadTarball = downloadTarball;
|
|
20
|
+
exports.deleteFiles = deleteFiles;
|
|
@@ -13,6 +13,10 @@ const { cloneDeep } = require("lodash/fp");
|
|
|
13
13
|
const { FieldTypes, AutoFieldSubTypes } = require("../../constants");
|
|
14
14
|
const { attachmentsRelativeURL } = require("../index");
|
|
15
15
|
const { processFormulas } = require("./utils");
|
|
16
|
+
const { deleteFiles } = require("../../utilities/fileSystem/utilities");
|
|
17
|
+
const { ObjectStoreBuckets } = require("../../constants");
|
|
18
|
+
const { isProdAppID, getDeployedAppID, dbExists } = require("@budibase/auth/db");
|
|
19
|
+
const CouchDB = require("../../db");
|
|
16
20
|
const BASE_AUTO_ID = 1;
|
|
17
21
|
/**
|
|
18
22
|
* A map of how we convert various properties in rows to each other based on the row type.
|
|
@@ -103,6 +107,22 @@ const TYPE_TRANSFORM_MAP = {
|
|
|
103
107
|
},
|
|
104
108
|
},
|
|
105
109
|
};
|
|
110
|
+
/**
|
|
111
|
+
* Given the old state of the row and the new one after an update, this will
|
|
112
|
+
* find the keys that have been removed in the updated row.
|
|
113
|
+
*/
|
|
114
|
+
function getRemovedAttachmentKeys(oldRow, row, attachmentKey) {
|
|
115
|
+
if (!oldRow[attachmentKey]) {
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
const oldKeys = oldRow[attachmentKey].map(attachment => attachment.key);
|
|
119
|
+
// no attachments in new row, all removed
|
|
120
|
+
if (!row[attachmentKey]) {
|
|
121
|
+
return oldKeys;
|
|
122
|
+
}
|
|
123
|
+
const newKeys = row[attachmentKey].map(attachment => attachment.key);
|
|
124
|
+
return oldKeys.filter(key => newKeys.indexOf(key) === -1);
|
|
125
|
+
}
|
|
106
126
|
/**
|
|
107
127
|
* This will update any auto columns that are found on the row/table with the correct information based on
|
|
108
128
|
* time now and the current logged in user making the request.
|
|
@@ -253,3 +273,46 @@ exports.outputProcessing = (ctx, table, rows, opts = { squash: true }) => __awai
|
|
|
253
273
|
}
|
|
254
274
|
return wasArray ? enriched : enriched[0];
|
|
255
275
|
});
|
|
276
|
+
/**
|
|
277
|
+
* Clean up any attachments that were attached to a row.
|
|
278
|
+
* @param {string} appId The ID of the app from which a row is being deleted.
|
|
279
|
+
* @param {object} table The table from which a row is being removed.
|
|
280
|
+
* @param {any} row optional - the row being removed.
|
|
281
|
+
* @param {any} rows optional - if multiple rows being deleted can do this in bulk.
|
|
282
|
+
* @param {any} oldRow optional - if updating a row this will determine the difference.
|
|
283
|
+
* @return {Promise<void>} When all attachments have been removed this will return.
|
|
284
|
+
*/
|
|
285
|
+
exports.cleanupAttachments = (appId, table, { row, rows, oldRow }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
286
|
+
if (!isProdAppID(appId)) {
|
|
287
|
+
const prodAppId = getDeployedAppID(appId);
|
|
288
|
+
// if prod exists, then don't allow deleting
|
|
289
|
+
const exists = yield dbExists(CouchDB, prodAppId);
|
|
290
|
+
if (exists) {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
let files = [];
|
|
295
|
+
function addFiles(row, key) {
|
|
296
|
+
if (row[key]) {
|
|
297
|
+
files = files.concat(row[key].map(attachment => attachment.key));
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
for (let [key, schema] of Object.entries(table.schema)) {
|
|
301
|
+
if (schema.type !== FieldTypes.ATTACHMENT) {
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
// if updating, need to manage the differences
|
|
305
|
+
if (oldRow && row) {
|
|
306
|
+
files = files.concat(getRemovedAttachmentKeys(oldRow, row, key));
|
|
307
|
+
}
|
|
308
|
+
else if (row) {
|
|
309
|
+
addFiles(row, key);
|
|
310
|
+
}
|
|
311
|
+
else if (rows) {
|
|
312
|
+
rows.forEach(row => addFiles(row, key));
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
if (files.length > 0) {
|
|
316
|
+
return deleteFiles(ObjectStoreBuckets.APPS, files);
|
|
317
|
+
}
|
|
318
|
+
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@budibase/server",
|
|
3
3
|
"email": "hi@budibase.com",
|
|
4
|
-
"version": "1.0.27-alpha.
|
|
4
|
+
"version": "1.0.27-alpha.8",
|
|
5
5
|
"description": "Budibase Web Server",
|
|
6
6
|
"main": "src/index.ts",
|
|
7
7
|
"repository": {
|
|
@@ -70,9 +70,9 @@
|
|
|
70
70
|
"license": "GPL-3.0",
|
|
71
71
|
"dependencies": {
|
|
72
72
|
"@apidevtools/swagger-parser": "^10.0.3",
|
|
73
|
-
"@budibase/auth": "^1.0.27-alpha.
|
|
74
|
-
"@budibase/client": "^1.0.27-alpha.
|
|
75
|
-
"@budibase/string-templates": "^1.0.27-alpha.
|
|
73
|
+
"@budibase/auth": "^1.0.27-alpha.8",
|
|
74
|
+
"@budibase/client": "^1.0.27-alpha.8",
|
|
75
|
+
"@budibase/string-templates": "^1.0.27-alpha.8",
|
|
76
76
|
"@bull-board/api": "^3.7.0",
|
|
77
77
|
"@bull-board/koa": "^3.7.0",
|
|
78
78
|
"@elastic/elasticsearch": "7.10.0",
|
|
@@ -165,5 +165,5 @@
|
|
|
165
165
|
"optionalDependencies": {
|
|
166
166
|
"oracledb": "^5.3.0"
|
|
167
167
|
},
|
|
168
|
-
"gitHead": "
|
|
168
|
+
"gitHead": "f74090d2eb0a4fefcd40e99aca1c53e45063511c"
|
|
169
169
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Query, QueryParameter } from "../../../../../../definitions/datasource"
|
|
2
|
+
import { URL } from "url"
|
|
2
3
|
|
|
3
4
|
export interface ImportInfo {
|
|
4
|
-
url: string
|
|
5
5
|
name: string
|
|
6
6
|
}
|
|
7
7
|
|
|
@@ -23,6 +23,7 @@ export abstract class ImportSource {
|
|
|
23
23
|
name: string,
|
|
24
24
|
method: string,
|
|
25
25
|
path: string,
|
|
26
|
+
url: URL,
|
|
26
27
|
queryString: string,
|
|
27
28
|
headers: object = {},
|
|
28
29
|
parameters: QueryParameter[] = [],
|
|
@@ -33,6 +34,7 @@ export abstract class ImportSource {
|
|
|
33
34
|
const transformer = "return data"
|
|
34
35
|
const schema = {}
|
|
35
36
|
path = this.processPath(path)
|
|
37
|
+
path = `${url.origin}/${path}`
|
|
36
38
|
queryString = this.processQuery(queryString)
|
|
37
39
|
const requestBody = JSON.stringify(body, null, 2)
|
|
38
40
|
|
|
@@ -60,16 +60,19 @@ export class Curl extends ImportSource {
|
|
|
60
60
|
return true
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
getUrl = (): URL => {
|
|
64
|
+
return new URL(this.curl.raw_url)
|
|
65
|
+
}
|
|
66
|
+
|
|
63
67
|
getInfo = async (): Promise<ImportInfo> => {
|
|
64
|
-
const url =
|
|
68
|
+
const url = this.getUrl()
|
|
65
69
|
return {
|
|
66
|
-
url: url.origin,
|
|
67
70
|
name: url.hostname,
|
|
68
71
|
}
|
|
69
72
|
}
|
|
70
73
|
|
|
71
74
|
getQueries = async (datasourceId: string): Promise<Query[]> => {
|
|
72
|
-
const url =
|
|
75
|
+
const url = this.getUrl()
|
|
73
76
|
const name = url.pathname
|
|
74
77
|
const path = url.pathname
|
|
75
78
|
const method = this.curl.method
|
|
@@ -87,6 +90,7 @@ export class Curl extends ImportSource {
|
|
|
87
90
|
name,
|
|
88
91
|
method,
|
|
89
92
|
path,
|
|
93
|
+
url,
|
|
90
94
|
queryString,
|
|
91
95
|
headers,
|
|
92
96
|
[],
|
|
@@ -2,6 +2,7 @@ import { ImportInfo } from "./base"
|
|
|
2
2
|
import { Query, QueryParameter } from "../../../../../definitions/datasource"
|
|
3
3
|
import { OpenAPIV2 } from "openapi-types"
|
|
4
4
|
import { OpenAPISource } from "./base/openapi"
|
|
5
|
+
import { URL } from "url"
|
|
5
6
|
|
|
6
7
|
const parameterNotRef = (
|
|
7
8
|
param: OpenAPIV2.Parameter | OpenAPIV2.ReferenceObject
|
|
@@ -55,20 +56,22 @@ export class OpenAPI2 extends OpenAPISource {
|
|
|
55
56
|
}
|
|
56
57
|
}
|
|
57
58
|
|
|
58
|
-
|
|
59
|
+
getUrl = (): URL => {
|
|
59
60
|
const scheme = this.document.schemes?.includes("https") ? "https" : "http"
|
|
60
61
|
const basePath = this.document.basePath || ""
|
|
61
62
|
const host = this.document.host || "<host>"
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
return new URL(`${scheme}://${host}${basePath}`)
|
|
64
|
+
}
|
|
64
65
|
|
|
66
|
+
getInfo = async (): Promise<ImportInfo> => {
|
|
67
|
+
const name = this.document.info.title || "Swagger Import"
|
|
65
68
|
return {
|
|
66
|
-
|
|
67
|
-
name: name,
|
|
69
|
+
name,
|
|
68
70
|
}
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
getQueries = async (datasourceId: string): Promise<Query[]> => {
|
|
74
|
+
const url = this.getUrl()
|
|
72
75
|
const queries = []
|
|
73
76
|
|
|
74
77
|
for (let [path, pathItem] of Object.entries(this.document.paths)) {
|
|
@@ -145,6 +148,7 @@ export class OpenAPI2 extends OpenAPISource {
|
|
|
145
148
|
name,
|
|
146
149
|
methodName,
|
|
147
150
|
path,
|
|
151
|
+
url,
|
|
148
152
|
queryString,
|
|
149
153
|
headers,
|
|
150
154
|
parameters,
|
|
@@ -35,7 +35,6 @@ describe("Curl Import", () => {
|
|
|
35
35
|
it("returns import info", async () => {
|
|
36
36
|
await init("get")
|
|
37
37
|
const info = await curl.getInfo()
|
|
38
|
-
expect(info.url).toBe("http://example.com")
|
|
39
38
|
expect(info.name).toBe("example.com")
|
|
40
39
|
})
|
|
41
40
|
|
|
@@ -67,8 +66,8 @@ describe("Curl Import", () => {
|
|
|
67
66
|
}
|
|
68
67
|
|
|
69
68
|
it("populates path", async () => {
|
|
70
|
-
await testPath("get", "")
|
|
71
|
-
await testPath("path", "paths/abc")
|
|
69
|
+
await testPath("get", "http://example.com/")
|
|
70
|
+
await testPath("path", "http://example.com/paths/abc")
|
|
72
71
|
})
|
|
73
72
|
|
|
74
73
|
const testHeaders = async (file, headers) => {
|
|
@@ -41,7 +41,6 @@ describe("OpenAPI2 Import", () => {
|
|
|
41
41
|
const testImportInfo = async (file, extension) => {
|
|
42
42
|
await init(file, extension)
|
|
43
43
|
const info = await openapi2.getInfo()
|
|
44
|
-
expect(info.url).toBe("https://petstore.swagger.io/v2")
|
|
45
44
|
expect(info.name).toBe("Swagger Petstore")
|
|
46
45
|
}
|
|
47
46
|
|
|
@@ -92,12 +91,12 @@ describe("OpenAPI2 Import", () => {
|
|
|
92
91
|
|
|
93
92
|
it("populates path", async () => {
|
|
94
93
|
const assertions = {
|
|
95
|
-
"createEntity" : "entities",
|
|
96
|
-
"getEntities" : "entities",
|
|
97
|
-
"getEntity" : "entities/{{entityId}}",
|
|
98
|
-
"updateEntity" : "entities/{{entityId}}",
|
|
99
|
-
"patchEntity" : "entities/{{entityId}}",
|
|
100
|
-
"deleteEntity" : "entities/{{entityId}}"
|
|
94
|
+
"createEntity" : "http://example.com/entities",
|
|
95
|
+
"getEntities" : "http://example.com/entities",
|
|
96
|
+
"getEntity" : "http://example.com/entities/{{entityId}}",
|
|
97
|
+
"updateEntity" : "http://example.com/entities/{{entityId}}",
|
|
98
|
+
"patchEntity" : "http://example.com/entities/{{entityId}}",
|
|
99
|
+
"deleteEntity" : "http://example.com/entities/{{entityId}}"
|
|
101
100
|
}
|
|
102
101
|
await runTests("crud", testPath, assertions)
|
|
103
102
|
})
|
|
@@ -51,30 +51,24 @@ describe("Rest Importer", () => {
|
|
|
51
51
|
await init(data)
|
|
52
52
|
const info = await restImporter.getInfo()
|
|
53
53
|
expect(info.name).toBe(assertions[key].name)
|
|
54
|
-
expect(info.url).toBe(assertions[key].url)
|
|
55
54
|
}
|
|
56
55
|
|
|
57
56
|
it("gets info", async () => {
|
|
58
57
|
const assertions = {
|
|
59
58
|
"oapi2CrudJson" : {
|
|
60
59
|
name: "CRUD",
|
|
61
|
-
url: "http://example.com"
|
|
62
60
|
},
|
|
63
61
|
"oapi2CrudYaml" : {
|
|
64
62
|
name: "CRUD",
|
|
65
|
-
url: "http://example.com"
|
|
66
63
|
},
|
|
67
64
|
"oapi2PetstoreJson" : {
|
|
68
65
|
name: "Swagger Petstore",
|
|
69
|
-
url: "https://petstore.swagger.io/v2"
|
|
70
66
|
},
|
|
71
67
|
"oapi2PetstoreYaml" :{
|
|
72
68
|
name: "Swagger Petstore",
|
|
73
|
-
url: "https://petstore.swagger.io/v2"
|
|
74
69
|
},
|
|
75
70
|
"curl": {
|
|
76
71
|
name: "example.com",
|
|
77
|
-
url: "http://example.com"
|
|
78
72
|
}
|
|
79
73
|
}
|
|
80
74
|
await runTest(testGetInfo, assertions)
|
|
@@ -8,6 +8,7 @@ const { BaseQueryVerbs } = require("../../../constants")
|
|
|
8
8
|
const { Thread, ThreadType } = require("../../../threads")
|
|
9
9
|
const { save: saveDatasource } = require("../datasource")
|
|
10
10
|
const { RestImporter } = require("./import")
|
|
11
|
+
const { invalidateDynamicVariables } = require("../../../threads/utils")
|
|
11
12
|
|
|
12
13
|
const Runner = new Thread(ThreadType.QUERY, { timeoutMs: 10000 })
|
|
13
14
|
|
|
@@ -166,8 +167,28 @@ exports.executeV2 = async function (ctx) {
|
|
|
166
167
|
return execute(ctx, { rowsOnly: false })
|
|
167
168
|
}
|
|
168
169
|
|
|
170
|
+
const removeDynamicVariables = async (db, queryId) => {
|
|
171
|
+
const query = await db.get(queryId)
|
|
172
|
+
const datasource = await db.get(query.datasourceId)
|
|
173
|
+
const dynamicVariables = datasource.config.dynamicVariables
|
|
174
|
+
|
|
175
|
+
if (dynamicVariables) {
|
|
176
|
+
// delete dynamic variables from the datasource
|
|
177
|
+
const newVariables = dynamicVariables.filter(dv => dv.queryId !== queryId)
|
|
178
|
+
datasource.config.dynamicVariables = newVariables
|
|
179
|
+
await db.put(datasource)
|
|
180
|
+
|
|
181
|
+
// invalidate the deleted variables
|
|
182
|
+
const variablesToDelete = dynamicVariables.filter(
|
|
183
|
+
dv => dv.queryId === queryId
|
|
184
|
+
)
|
|
185
|
+
await invalidateDynamicVariables(variablesToDelete)
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
169
189
|
exports.destroy = async function (ctx) {
|
|
170
190
|
const db = new CouchDB(ctx.appId)
|
|
191
|
+
await removeDynamicVariables(db, ctx.params.queryId)
|
|
171
192
|
await db.remove(ctx.params.queryId, ctx.params.revId)
|
|
172
193
|
ctx.message = `Query deleted.`
|
|
173
194
|
ctx.status = 200
|
|
@@ -11,6 +11,7 @@ const {
|
|
|
11
11
|
inputProcessing,
|
|
12
12
|
outputProcessing,
|
|
13
13
|
processAutoColumn,
|
|
14
|
+
cleanupAttachments,
|
|
14
15
|
} = require("../../../utilities/rowProcessor")
|
|
15
16
|
const { FieldTypes } = require("../../../constants")
|
|
16
17
|
const { isEqual } = require("lodash")
|
|
@@ -25,6 +26,7 @@ const {
|
|
|
25
26
|
getFromDesignDoc,
|
|
26
27
|
getFromMemoryDoc,
|
|
27
28
|
} = require("../view/utils")
|
|
29
|
+
const { cloneDeep } = require("lodash/fp")
|
|
28
30
|
|
|
29
31
|
const CALCULATION_TYPES = {
|
|
30
32
|
SUM: "sum",
|
|
@@ -109,14 +111,14 @@ exports.patch = async ctx => {
|
|
|
109
111
|
const inputs = ctx.request.body
|
|
110
112
|
const tableId = inputs.tableId
|
|
111
113
|
const isUserTable = tableId === InternalTables.USER_METADATA
|
|
112
|
-
let
|
|
114
|
+
let oldRow
|
|
113
115
|
try {
|
|
114
|
-
|
|
116
|
+
oldRow = await db.get(inputs._id)
|
|
115
117
|
} catch (err) {
|
|
116
118
|
if (isUserTable) {
|
|
117
119
|
// don't include the rev, it'll be the global rev
|
|
118
120
|
// this time
|
|
119
|
-
|
|
121
|
+
oldRow = {
|
|
120
122
|
_id: inputs._id,
|
|
121
123
|
}
|
|
122
124
|
} else {
|
|
@@ -125,13 +127,14 @@ exports.patch = async ctx => {
|
|
|
125
127
|
}
|
|
126
128
|
let dbTable = await db.get(tableId)
|
|
127
129
|
// need to build up full patch fields before coerce
|
|
130
|
+
let combinedRow = cloneDeep(oldRow)
|
|
128
131
|
for (let key of Object.keys(inputs)) {
|
|
129
132
|
if (!dbTable.schema[key]) continue
|
|
130
|
-
|
|
133
|
+
combinedRow[key] = inputs[key]
|
|
131
134
|
}
|
|
132
135
|
|
|
133
136
|
// this returns the table and row incase they have been updated
|
|
134
|
-
let { table, row } = inputProcessing(ctx.user, dbTable,
|
|
137
|
+
let { table, row } = inputProcessing(ctx.user, dbTable, combinedRow)
|
|
135
138
|
const validateResult = await validate({
|
|
136
139
|
row,
|
|
137
140
|
table,
|
|
@@ -149,6 +152,8 @@ exports.patch = async ctx => {
|
|
|
149
152
|
tableId: row.tableId,
|
|
150
153
|
table,
|
|
151
154
|
})
|
|
155
|
+
// check if any attachments removed
|
|
156
|
+
await cleanupAttachments(appId, table, { oldRow, row })
|
|
152
157
|
|
|
153
158
|
if (isUserTable) {
|
|
154
159
|
// the row has been updated, need to put it into the ctx
|
|
@@ -295,6 +300,8 @@ exports.destroy = async function (ctx) {
|
|
|
295
300
|
row,
|
|
296
301
|
tableId: row.tableId,
|
|
297
302
|
})
|
|
303
|
+
// remove any attachments that were on the row from object storage
|
|
304
|
+
await cleanupAttachments(appId, table, { row })
|
|
298
305
|
|
|
299
306
|
let response
|
|
300
307
|
if (ctx.params.tableId === InternalTables.USER_METADATA) {
|
|
@@ -341,6 +348,8 @@ exports.bulkDestroy = async ctx => {
|
|
|
341
348
|
} else {
|
|
342
349
|
await db.bulkDocs(rows.map(row => ({ ...row, _deleted: true })))
|
|
343
350
|
}
|
|
351
|
+
// remove any attachments that were on the rows from object storage
|
|
352
|
+
await cleanupAttachments(appId, table, { rows })
|
|
344
353
|
await Promise.all(updates)
|
|
345
354
|
return { response: { ok: true }, rows }
|
|
346
355
|
}
|
package/src/integrations/rest.ts
CHANGED
|
@@ -171,7 +171,7 @@ module RestModule {
|
|
|
171
171
|
getUrl(path: string, queryString: string): string {
|
|
172
172
|
const main = `${path}?${queryString}`
|
|
173
173
|
let complete = main
|
|
174
|
-
if (this.config.url && !main.startsWith(
|
|
174
|
+
if (this.config.url && !main.startsWith("http")) {
|
|
175
175
|
complete = !this.config.url ? main : `${this.config.url}/${main}`
|
|
176
176
|
}
|
|
177
177
|
if (!complete.startsWith("http")) {
|
package/src/threads/utils.js
CHANGED
|
@@ -42,10 +42,11 @@ exports.checkCacheForDynamicVariable = async (queryId, variable) => {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
exports.invalidateDynamicVariables = async cachedVars => {
|
|
45
|
+
const cache = await getClient()
|
|
45
46
|
let promises = []
|
|
46
47
|
for (let variable of cachedVars) {
|
|
47
48
|
promises.push(
|
|
48
|
-
|
|
49
|
+
cache.delete(makeVariableKey(variable.queryId, variable.name))
|
|
49
50
|
)
|
|
50
51
|
}
|
|
51
52
|
await Promise.all(promises)
|
|
@@ -2,6 +2,7 @@ const {
|
|
|
2
2
|
ObjectStore,
|
|
3
3
|
makeSureBucketExists,
|
|
4
4
|
upload,
|
|
5
|
+
deleteFiles,
|
|
5
6
|
streamUpload,
|
|
6
7
|
retrieve,
|
|
7
8
|
retrieveToTmp,
|
|
@@ -28,3 +29,4 @@ exports.retrieveToTmp = retrieveToTmp
|
|
|
28
29
|
exports.deleteFolder = deleteFolder
|
|
29
30
|
exports.uploadDirectory = uploadDirectory
|
|
30
31
|
exports.downloadTarball = downloadTarball
|
|
32
|
+
exports.deleteFiles = deleteFiles
|
|
@@ -3,6 +3,10 @@ const { cloneDeep } = require("lodash/fp")
|
|
|
3
3
|
const { FieldTypes, AutoFieldSubTypes } = require("../../constants")
|
|
4
4
|
const { attachmentsRelativeURL } = require("../index")
|
|
5
5
|
const { processFormulas } = require("./utils")
|
|
6
|
+
const { deleteFiles } = require("../../utilities/fileSystem/utilities")
|
|
7
|
+
const { ObjectStoreBuckets } = require("../../constants")
|
|
8
|
+
const { isProdAppID, getDeployedAppID, dbExists } = require("@budibase/auth/db")
|
|
9
|
+
const CouchDB = require("../../db")
|
|
6
10
|
|
|
7
11
|
const BASE_AUTO_ID = 1
|
|
8
12
|
|
|
@@ -95,6 +99,23 @@ const TYPE_TRANSFORM_MAP = {
|
|
|
95
99
|
},
|
|
96
100
|
}
|
|
97
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Given the old state of the row and the new one after an update, this will
|
|
104
|
+
* find the keys that have been removed in the updated row.
|
|
105
|
+
*/
|
|
106
|
+
function getRemovedAttachmentKeys(oldRow, row, attachmentKey) {
|
|
107
|
+
if (!oldRow[attachmentKey]) {
|
|
108
|
+
return []
|
|
109
|
+
}
|
|
110
|
+
const oldKeys = oldRow[attachmentKey].map(attachment => attachment.key)
|
|
111
|
+
// no attachments in new row, all removed
|
|
112
|
+
if (!row[attachmentKey]) {
|
|
113
|
+
return oldKeys
|
|
114
|
+
}
|
|
115
|
+
const newKeys = row[attachmentKey].map(attachment => attachment.key)
|
|
116
|
+
return oldKeys.filter(key => newKeys.indexOf(key) === -1)
|
|
117
|
+
}
|
|
118
|
+
|
|
98
119
|
/**
|
|
99
120
|
* This will update any auto columns that are found on the row/table with the correct information based on
|
|
100
121
|
* time now and the current logged in user making the request.
|
|
@@ -272,3 +293,45 @@ exports.outputProcessing = async (
|
|
|
272
293
|
}
|
|
273
294
|
return wasArray ? enriched : enriched[0]
|
|
274
295
|
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Clean up any attachments that were attached to a row.
|
|
299
|
+
* @param {string} appId The ID of the app from which a row is being deleted.
|
|
300
|
+
* @param {object} table The table from which a row is being removed.
|
|
301
|
+
* @param {any} row optional - the row being removed.
|
|
302
|
+
* @param {any} rows optional - if multiple rows being deleted can do this in bulk.
|
|
303
|
+
* @param {any} oldRow optional - if updating a row this will determine the difference.
|
|
304
|
+
* @return {Promise<void>} When all attachments have been removed this will return.
|
|
305
|
+
*/
|
|
306
|
+
exports.cleanupAttachments = async (appId, table, { row, rows, oldRow }) => {
|
|
307
|
+
if (!isProdAppID(appId)) {
|
|
308
|
+
const prodAppId = getDeployedAppID(appId)
|
|
309
|
+
// if prod exists, then don't allow deleting
|
|
310
|
+
const exists = await dbExists(CouchDB, prodAppId)
|
|
311
|
+
if (exists) {
|
|
312
|
+
return
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
let files = []
|
|
316
|
+
function addFiles(row, key) {
|
|
317
|
+
if (row[key]) {
|
|
318
|
+
files = files.concat(row[key].map(attachment => attachment.key))
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
for (let [key, schema] of Object.entries(table.schema)) {
|
|
322
|
+
if (schema.type !== FieldTypes.ATTACHMENT) {
|
|
323
|
+
continue
|
|
324
|
+
}
|
|
325
|
+
// if updating, need to manage the differences
|
|
326
|
+
if (oldRow && row) {
|
|
327
|
+
files = files.concat(getRemovedAttachmentKeys(oldRow, row, key))
|
|
328
|
+
} else if (row) {
|
|
329
|
+
addFiles(row, key)
|
|
330
|
+
} else if (rows) {
|
|
331
|
+
rows.forEach(row => addFiles(row, key))
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
if (files.length > 0) {
|
|
335
|
+
return deleteFiles(ObjectStoreBuckets.APPS, files)
|
|
336
|
+
}
|
|
337
|
+
}
|