@budibase/server 1.0.46-alpha.7 → 1.0.48
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.dd9e386f.css → index.39e01193.css} +1 -1
- package/builder/assets/{index.af9e71d8.js → index.e083dcaf.js} +221 -223
- package/builder/assets/{vendor.3bd2f661.js → vendor.f9faf6ab.js} +12 -12
- package/builder/index.html +3 -3
- package/coverage/clover.xml +1637 -1793
- package/coverage/coverage-final.json +94 -98
- 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 +126 -210
- package/coverage/lcov-report/api/controllers/auth.js.html +1 -1
- package/coverage/lcov-report/api/controllers/automation.js.html +21 -21
- 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 +4 -4
- package/coverage/lcov-report/api/controllers/datasource.js.html +36 -72
- package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
- package/coverage/lcov-report/{migrations/usageQuotas/syncRows.js.html → api/controllers/hosting.js.html} +44 -41
- package/coverage/lcov-report/api/controllers/index.html +42 -27
- package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
- package/coverage/lcov-report/api/controllers/layout.js.html +6 -6
- package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
- package/coverage/lcov-report/api/controllers/permission.js.html +15 -15
- package/coverage/lcov-report/api/controllers/query/index.html +1 -1
- package/coverage/lcov-report/api/controllers/query/index.js.html +19 -19
- package/coverage/lcov-report/api/controllers/query/validation.js.html +6 -6
- package/coverage/lcov-report/api/controllers/role.js.html +9 -9
- package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/external.js.html +16 -16
- package/coverage/lcov-report/api/controllers/row/index.html +15 -15
- package/coverage/lcov-report/api/controllers/row/index.js.html +26 -26
- package/coverage/lcov-report/api/controllers/row/internal.js.html +44 -44
- package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +8 -8
- package/coverage/lcov-report/api/controllers/row/utils.js.html +57 -39
- package/coverage/lcov-report/api/controllers/screen.js.html +7 -7
- package/coverage/lcov-report/api/controllers/script.js.html +4 -4
- package/coverage/lcov-report/api/controllers/table/external.js.html +12 -12
- package/coverage/lcov-report/api/controllers/table/index.html +32 -32
- package/coverage/lcov-report/api/controllers/table/index.js.html +39 -57
- package/coverage/lcov-report/api/controllers/table/internal.js.html +34 -40
- package/coverage/lcov-report/api/controllers/table/utils.js.html +122 -83
- package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
- package/coverage/lcov-report/api/controllers/user.js.html +20 -20
- package/coverage/lcov-report/api/controllers/view/exporters.js.html +4 -4
- package/coverage/lcov-report/api/controllers/view/index.html +1 -1
- package/coverage/lcov-report/api/controllers/view/index.js.html +14 -14
- package/coverage/lcov-report/api/controllers/view/utils.js.html +11 -11
- package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +7 -7
- package/coverage/lcov-report/api/controllers/webhook.js.html +15 -15
- package/coverage/lcov-report/api/index.html +1 -1
- package/coverage/lcov-report/api/index.js.html +10 -10
- 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/{migrations/usageQuotas/syncApps.js.html → api/routes/hosting.js.html} +27 -42
- package/coverage/lcov-report/api/routes/index.html +22 -7
- package/coverage/lcov-report/api/routes/index.js.html +10 -4
- 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 +2 -17
- 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 +24 -24
- package/coverage/lcov-report/automations/automationUtils.js.html +5 -5
- package/coverage/lcov-report/automations/bullboard.js.html +16 -16
- 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 +6 -6
- package/coverage/lcov-report/automations/steps/createRow.js.html +19 -13
- package/coverage/lcov-report/automations/steps/delay.js.html +4 -4
- package/coverage/lcov-report/automations/steps/deleteRow.js.html +20 -11
- package/coverage/lcov-report/automations/steps/discord.js.html +7 -7
- package/coverage/lcov-report/automations/steps/executeQuery.js.html +6 -6
- package/coverage/lcov-report/automations/steps/executeScript.js.html +6 -6
- package/coverage/lcov-report/automations/steps/filter.js.html +7 -7
- package/coverage/lcov-report/automations/steps/index.html +13 -13
- package/coverage/lcov-report/automations/steps/integromat.js.html +5 -5
- package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +8 -8
- package/coverage/lcov-report/automations/steps/queryRows.js.html +10 -10
- package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +5 -5
- package/coverage/lcov-report/automations/steps/serverLog.js.html +3 -3
- package/coverage/lcov-report/automations/steps/slack.js.html +5 -5
- package/coverage/lcov-report/automations/steps/updateRow.js.html +6 -6
- package/coverage/lcov-report/automations/steps/utils.js.html +3 -3
- package/coverage/lcov-report/automations/steps/zapier.js.html +5 -5
- package/coverage/lcov-report/automations/triggerInfo/app.js.html +2 -2
- package/coverage/lcov-report/automations/triggerInfo/cron.js.html +2 -2
- package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/index.js.html +8 -8
- package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +2 -2
- package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +2 -2
- package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +2 -2
- package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +2 -2
- package/coverage/lcov-report/automations/triggers.js.html +18 -18
- package/coverage/lcov-report/automations/utils.js.html +32 -32
- package/coverage/lcov-report/constants/index.html +11 -11
- package/coverage/lcov-report/constants/index.js.html +37 -40
- package/coverage/lcov-report/constants/layouts.js.html +5 -5
- package/coverage/lcov-report/constants/screens.js.html +4 -4
- package/coverage/lcov-report/db/client.js.html +18 -18
- package/coverage/lcov-report/db/inMemoryView.js.html +7 -7
- package/coverage/lcov-report/db/index.html +15 -15
- package/coverage/lcov-report/db/index.js.html +3 -3
- package/coverage/lcov-report/db/linkedRows/LinkController.js.html +18 -18
- package/coverage/lcov-report/db/linkedRows/index.html +1 -1
- package/coverage/lcov-report/db/linkedRows/index.js.html +31 -31
- package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +15 -15
- package/coverage/lcov-report/db/newid.js.html +4 -4
- package/coverage/lcov-report/db/utils.js.html +85 -85
- 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 +5 -5
- package/coverage/lcov-report/events/utils.js.html +3 -3
- package/coverage/lcov-report/index.html +86 -116
- 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 +11 -11
- package/coverage/lcov-report/middleware/builder.js.html +8 -8
- package/coverage/lcov-report/middleware/currentapp.js.html +29 -29
- package/coverage/lcov-report/middleware/index.html +20 -20
- package/coverage/lcov-report/middleware/joi-validator.js.html +3 -3
- 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 +41 -275
- package/coverage/lcov-report/middleware/utils.js.html +2 -2
- package/coverage/lcov-report/threads/automation.js.html +1 -1
- package/coverage/lcov-report/threads/index.html +15 -15
- package/coverage/lcov-report/threads/index.js.html +10 -10
- package/coverage/lcov-report/threads/query.js.html +8 -23
- package/coverage/lcov-report/threads/utils.js.html +14 -14
- package/coverage/lcov-report/utilities/bcrypt.js.html +1 -1
- package/coverage/lcov-report/utilities/budibaseDir.js.html +7 -7
- package/coverage/lcov-report/utilities/centralPath.js.html +4 -4
- package/coverage/lcov-report/utilities/csvParser.js.html +6 -6
- package/coverage/lcov-report/utilities/global.js.html +26 -26
- package/coverage/lcov-report/utilities/index.html +19 -19
- package/coverage/lcov-report/utilities/index.js.html +25 -25
- package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +8 -8
- 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 +1 -1
- package/coverage/lcov-report/utilities/rowProcessor/index.js.html +53 -53
- package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +10 -10
- package/coverage/lcov-report/utilities/scriptRunner.js.html +5 -5
- package/coverage/lcov-report/utilities/security.js.html +8 -8
- package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
- package/coverage/lcov-report/utilities/users.js.html +5 -5
- package/coverage/lcov-report/utilities/workerRequests.js.html +108 -39
- package/coverage/lcov.info +2332 -2599
- package/dist/api/controllers/application.js +20 -49
- package/dist/api/controllers/datasource.js +0 -11
- package/dist/api/controllers/hosting.js +30 -0
- package/dist/api/controllers/row/ExternalRequest.js +2 -1
- package/dist/api/controllers/row/utils.js +8 -6
- package/dist/api/controllers/static/index.js +10 -59
- package/dist/api/controllers/table/index.js +4 -10
- package/dist/api/controllers/table/internal.js +0 -2
- package/dist/api/controllers/table/utils.js +17 -11
- package/dist/api/routes/hosting.js +11 -0
- package/dist/api/routes/index.js +2 -0
- package/dist/api/routes/static.js +1 -2
- package/dist/automations/steps/createRow.js +4 -2
- package/dist/automations/steps/deleteRow.js +4 -1
- package/dist/constants/index.js +5 -8
- package/dist/definitions/datasource.js +0 -1
- package/dist/environment.js +0 -1
- package/dist/integrations/base/sql.js +6 -13
- package/dist/integrations/index.js +0 -3
- package/dist/integrations/utils.js +9 -56
- package/dist/middleware/usageQuota.js +13 -82
- package/dist/package.json +5 -8
- package/dist/tests/utilities/TestConfiguration.js +1 -3
- package/dist/threads/query.js +0 -4
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utilities/{usageQuota/index.js → usageQuota.js} +31 -44
- package/dist/utilities/workerRequests.js +20 -0
- package/nodemon.json +1 -1
- package/package.json +6 -9
- package/src/api/controllers/application.js +24 -52
- package/src/api/controllers/datasource.js +0 -12
- package/src/api/controllers/hosting.js +22 -0
- package/src/api/controllers/row/ExternalRequest.ts +1 -1
- package/src/api/controllers/row/utils.js +12 -6
- package/src/api/controllers/static/index.js +10 -63
- package/src/api/controllers/table/index.js +9 -15
- package/src/api/controllers/table/internal.js +0 -2
- package/src/api/controllers/table/utils.js +24 -11
- package/src/api/routes/hosting.js +13 -0
- package/src/api/routes/index.js +2 -0
- package/src/api/routes/static.js +0 -5
- package/src/api/routes/tests/application.spec.js +2 -2
- package/src/api/routes/tests/hosting.spec.js +36 -0
- package/src/automations/steps/createRow.js +4 -2
- package/src/automations/steps/deleteRow.js +4 -1
- package/src/constants/index.js +8 -9
- package/src/definitions/datasource.ts +0 -3
- package/src/environment.js +0 -1
- package/src/integrations/base/sql.ts +7 -14
- package/src/integrations/index.ts +0 -3
- package/src/integrations/tests/sql.spec.js +0 -16
- package/src/integrations/utils.ts +11 -70
- package/src/middleware/tests/usageQuota.spec.js +24 -18
- package/src/middleware/usageQuota.js +15 -93
- package/src/tests/utilities/TestConfiguration.js +1 -3
- package/src/threads/query.js +0 -5
- package/src/utilities/usageQuota.js +73 -0
- package/src/utilities/workerRequests.js +23 -0
- package/coverage/lcov-report/migrations/usageQuotas/index.html +0 -141
- package/coverage/lcov-report/migrations/usageQuotas/index.js.html +0 -152
- package/coverage/lcov-report/utilities/usageQuota/index.html +0 -141
- package/coverage/lcov-report/utilities/usageQuota/index.js.html +0 -356
- package/coverage/lcov-report/utilities/usageQuota/rows.js.html +0 -302
- package/coverage/lcov-report/utilities/usageQuota/usageQuoteReset.js.html +0 -134
- package/dist/integrations/googlesheets.js +0 -340
- package/dist/migrations/usageQuotas/index.js +0 -24
- package/dist/migrations/usageQuotas/syncApps.js +0 -26
- package/dist/migrations/usageQuotas/syncRows.js +0 -29
- package/dist/utilities/usageQuota/rows.js +0 -77
- package/dist/utilities/usageQuota/usageQuoteReset.js +0 -16
- package/src/api/routes/tests/static.spec.js +0 -98
- package/src/integrations/googlesheets.ts +0 -353
- package/src/migrations/tests/usageQuotas/index.spec.js +0 -27
- package/src/migrations/tests/usageQuotas/syncApps.spec.js +0 -37
- package/src/migrations/tests/usageQuotas/syncRows.spec.js +0 -43
- package/src/migrations/usageQuotas/index.js +0 -24
- package/src/migrations/usageQuotas/syncApps.js +0 -18
- package/src/migrations/usageQuotas/syncRows.js +0 -21
- package/src/utilities/tests/usageQuota/usageQuota.spec.js +0 -72
- package/src/utilities/usageQuota/index.js +0 -92
- package/src/utilities/usageQuota/rows.js +0 -74
- package/src/utilities/usageQuota/usageQuoteReset.js +0 -18
|
@@ -8,24 +8,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
-
const env = require("
|
|
12
|
-
const { getGlobalDB
|
|
11
|
+
const env = require("../environment");
|
|
12
|
+
const { getGlobalDB } = require("@budibase/backend-core/tenancy");
|
|
13
13
|
const { StaticDatabases, generateNewUsageQuotaDoc, } = require("@budibase/backend-core/db");
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
// check if there are any tenants without limits
|
|
18
|
-
if (env.EXCLUDE_QUOTAS_TENANTS) {
|
|
19
|
-
const excludedTenants = env.EXCLUDE_QUOTAS_TENANTS.replace(/\s/g, "").split(",");
|
|
20
|
-
const tenantId = getTenantId();
|
|
21
|
-
if (excludedTenants.includes(tenantId)) {
|
|
22
|
-
return false;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
return true;
|
|
26
|
-
}
|
|
27
|
-
return false;
|
|
28
|
-
};
|
|
14
|
+
function getNewQuotaReset() {
|
|
15
|
+
return Date.now() + 2592000000;
|
|
16
|
+
}
|
|
29
17
|
exports.Properties = {
|
|
30
18
|
ROW: "rows",
|
|
31
19
|
UPLOAD: "storage",
|
|
@@ -33,21 +21,21 @@ exports.Properties = {
|
|
|
33
21
|
USER: "users",
|
|
34
22
|
AUTOMATION: "automationRuns",
|
|
35
23
|
APPS: "apps",
|
|
36
|
-
EMAILS: "emails",
|
|
24
|
+
EMAILS: "emails",
|
|
37
25
|
};
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
26
|
+
function getUsageQuotaDoc(db) {
|
|
27
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
28
|
+
let quota;
|
|
29
|
+
try {
|
|
30
|
+
quota = yield db.get(StaticDatabases.PLATFORM_INFO.docs.usageQuota);
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
// doc doesn't exist. Create it
|
|
34
|
+
quota = yield db.post(generateNewUsageQuotaDoc());
|
|
35
|
+
}
|
|
36
|
+
return quota;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
51
39
|
/**
|
|
52
40
|
* Given a specified tenantId this will add to the usage object for the specified property.
|
|
53
41
|
* @param {string} property The property which is to be added to (within the nested usageQuota object).
|
|
@@ -55,28 +43,27 @@ exports.getUsageQuotaDoc = (db) => __awaiter(void 0, void 0, void 0, function* (
|
|
|
55
43
|
* @returns {Promise<void>} When this completes the API key will now be up to date - the quota period may have
|
|
56
44
|
* also been reset after this call.
|
|
57
45
|
*/
|
|
58
|
-
exports.update = (property, usage
|
|
59
|
-
if (!
|
|
46
|
+
exports.update = (property, usage) => __awaiter(void 0, void 0, void 0, function* () {
|
|
47
|
+
if (!env.USE_QUOTAS) {
|
|
60
48
|
return;
|
|
61
49
|
}
|
|
62
50
|
try {
|
|
63
51
|
const db = getGlobalDB();
|
|
64
|
-
const quota = yield
|
|
52
|
+
const quota = yield getUsageQuotaDoc(db);
|
|
53
|
+
// Check if the quota needs reset
|
|
54
|
+
if (Date.now() >= quota.quotaReset) {
|
|
55
|
+
quota.quotaReset = getNewQuotaReset();
|
|
56
|
+
for (let prop of Object.keys(quota.usageQuota)) {
|
|
57
|
+
quota.usageQuota[prop] = 0;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
65
60
|
// increment the quota
|
|
66
61
|
quota.usageQuota[property] += usage;
|
|
67
|
-
if (quota.usageQuota[property] > quota.usageLimits[property]
|
|
68
|
-
usage > 0 // allow for decrementing usage when the quota is already exceeded
|
|
69
|
-
) {
|
|
62
|
+
if (quota.usageQuota[property] > quota.usageLimits[property]) {
|
|
70
63
|
throw new Error(`You have exceeded your usage quota of ${quota.usageLimits[property]} ${property}.`);
|
|
71
64
|
}
|
|
72
|
-
if (quota.usageQuota[property] < 0) {
|
|
73
|
-
// never go negative if the quota has previously been exceeded
|
|
74
|
-
quota.usageQuota[property] = 0;
|
|
75
|
-
}
|
|
76
65
|
// update the usage quotas
|
|
77
|
-
|
|
78
|
-
yield db.put(quota);
|
|
79
|
-
}
|
|
66
|
+
yield db.put(quota);
|
|
80
67
|
}
|
|
81
68
|
catch (err) {
|
|
82
69
|
console.error(`Error updating usage quotas for ${property}`, err);
|
|
@@ -61,6 +61,26 @@ exports.sendSmtpEmail = (to, from, subject, contents, automation) => __awaiter(v
|
|
|
61
61
|
}
|
|
62
62
|
return response.json();
|
|
63
63
|
});
|
|
64
|
+
exports.getDeployedApps = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
65
|
+
try {
|
|
66
|
+
const response = yield fetch(checkSlashesInUrl(env.WORKER_URL + `/api/apps`), request(null, {
|
|
67
|
+
method: "GET",
|
|
68
|
+
}));
|
|
69
|
+
const json = yield response.json();
|
|
70
|
+
const apps = {};
|
|
71
|
+
for (let [key, value] of Object.entries(json)) {
|
|
72
|
+
if (value.url) {
|
|
73
|
+
value.url = value.url.toLowerCase();
|
|
74
|
+
apps[key.toLowerCase()] = value;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return apps;
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
// error, cannot determine deployed apps, don't stop app creation - sort this later
|
|
81
|
+
return {};
|
|
82
|
+
}
|
|
83
|
+
});
|
|
64
84
|
exports.getGlobalSelf = (ctx, appId = null) => __awaiter(void 0, void 0, void 0, function* () {
|
|
65
85
|
const endpoint = `/api/global/users/self`;
|
|
66
86
|
const response = yield fetch(checkSlashesInUrl(env.WORKER_URL + endpoint),
|
package/nodemon.json
CHANGED
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.
|
|
4
|
+
"version": "1.0.48",
|
|
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/backend-core": "^1.0.
|
|
74
|
-
"@budibase/client": "^1.0.
|
|
75
|
-
"@budibase/string-templates": "^1.0.
|
|
73
|
+
"@budibase/backend-core": "^1.0.48",
|
|
74
|
+
"@budibase/client": "^1.0.48",
|
|
75
|
+
"@budibase/string-templates": "^1.0.48",
|
|
76
76
|
"@bull-board/api": "^3.7.0",
|
|
77
77
|
"@bull-board/koa": "^3.7.0",
|
|
78
78
|
"@elastic/elasticsearch": "7.10.0",
|
|
@@ -92,8 +92,6 @@
|
|
|
92
92
|
"fix-path": "3.0.0",
|
|
93
93
|
"form-data": "^4.0.0",
|
|
94
94
|
"fs-extra": "8.1.0",
|
|
95
|
-
"google-auth-library": "^7.11.0",
|
|
96
|
-
"google-spreadsheet": "^3.2.0",
|
|
97
95
|
"jimp": "0.16.1",
|
|
98
96
|
"joi": "17.2.1",
|
|
99
97
|
"js-yaml": "^4.1.0",
|
|
@@ -112,7 +110,7 @@
|
|
|
112
110
|
"mongodb": "3.6.3",
|
|
113
111
|
"mssql": "6.2.3",
|
|
114
112
|
"mysql2": "^2.3.1",
|
|
115
|
-
"node-fetch": "2.6.
|
|
113
|
+
"node-fetch": "2.6.0",
|
|
116
114
|
"open": "^8.4.0",
|
|
117
115
|
"pg": "8.5.1",
|
|
118
116
|
"pino-pretty": "4.0.0",
|
|
@@ -141,7 +139,6 @@
|
|
|
141
139
|
"@jest/test-sequencer": "^24.8.0",
|
|
142
140
|
"@types/apidoc": "^0.50.0",
|
|
143
141
|
"@types/bull": "^3.15.1",
|
|
144
|
-
"@types/google-spreadsheet": "^3.1.5",
|
|
145
142
|
"@types/jest": "^26.0.23",
|
|
146
143
|
"@types/koa": "^2.13.3",
|
|
147
144
|
"@types/koa-router": "^7.4.2",
|
|
@@ -168,5 +165,5 @@
|
|
|
168
165
|
"optionalDependencies": {
|
|
169
166
|
"oracledb": "^5.3.0"
|
|
170
167
|
},
|
|
171
|
-
"gitHead": "
|
|
168
|
+
"gitHead": "a5f51d83ba37e2361daf4ff579bb039a2247dd5e"
|
|
172
169
|
}
|
|
@@ -33,7 +33,10 @@ const {
|
|
|
33
33
|
Replication,
|
|
34
34
|
} = require("@budibase/backend-core/db")
|
|
35
35
|
const { USERS_TABLE_SCHEMA } = require("../../constants")
|
|
36
|
-
const {
|
|
36
|
+
const {
|
|
37
|
+
getDeployedApps,
|
|
38
|
+
removeAppFromUserRoles,
|
|
39
|
+
} = require("../../utilities/workerRequests")
|
|
37
40
|
const { clientLibraryPath, stringToReadStream } = require("../../utilities")
|
|
38
41
|
const { getAllLocks } = require("../../utilities/redis")
|
|
39
42
|
const {
|
|
@@ -75,42 +78,29 @@ function getUserRoleId(ctx) {
|
|
|
75
78
|
: ctx.user.role._id
|
|
76
79
|
}
|
|
77
80
|
|
|
78
|
-
async function
|
|
79
|
-
// construct the url
|
|
81
|
+
async function getAppUrlIfNotInUse(ctx) {
|
|
80
82
|
let url
|
|
81
83
|
if (ctx.request.body.url) {
|
|
82
|
-
// if the url is provided, use that
|
|
83
84
|
url = encodeURI(ctx.request.body.url)
|
|
84
85
|
} else if (ctx.request.body.name) {
|
|
85
|
-
// otherwise use the name
|
|
86
86
|
url = encodeURI(`${ctx.request.body.name}`)
|
|
87
87
|
}
|
|
88
88
|
if (url) {
|
|
89
89
|
url = `/${url.replace(URL_REGEX_SLASH, "")}`.toLowerCase()
|
|
90
90
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const checkAppUrl = (ctx, apps, url, currentAppId) => {
|
|
95
|
-
if (currentAppId) {
|
|
96
|
-
apps = apps.filter(app => app.appId !== currentAppId)
|
|
97
|
-
}
|
|
98
|
-
if (apps.some(app => app.url === url)) {
|
|
99
|
-
ctx.throw(400, "App URL is already in use.")
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const checkAppName = (ctx, apps, name, currentAppId) => {
|
|
104
|
-
// TODO: Replace with Joi
|
|
105
|
-
if (!name) {
|
|
106
|
-
ctx.throw(400, "Name is required")
|
|
91
|
+
if (!env.SELF_HOSTED) {
|
|
92
|
+
return url
|
|
107
93
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
ctx.
|
|
94
|
+
const deployedApps = await getDeployedApps()
|
|
95
|
+
if (
|
|
96
|
+
url &&
|
|
97
|
+
deployedApps[url] != null &&
|
|
98
|
+
ctx.params != null &&
|
|
99
|
+
deployedApps[url].appId !== ctx.params.appId
|
|
100
|
+
) {
|
|
101
|
+
ctx.throw(400, "App name/URL is already in use.")
|
|
113
102
|
}
|
|
103
|
+
return url
|
|
114
104
|
}
|
|
115
105
|
|
|
116
106
|
async function createInstance(template) {
|
|
@@ -216,12 +206,6 @@ exports.fetchAppPackage = async ctx => {
|
|
|
216
206
|
}
|
|
217
207
|
|
|
218
208
|
exports.create = async ctx => {
|
|
219
|
-
const apps = await getAllApps(CouchDB, { dev: true })
|
|
220
|
-
const name = ctx.request.body.name
|
|
221
|
-
checkAppName(ctx, apps, name)
|
|
222
|
-
const url = await getAppUrl(ctx)
|
|
223
|
-
checkAppUrl(ctx, apps, url)
|
|
224
|
-
|
|
225
209
|
const { useTemplate, templateKey, templateString } = ctx.request.body
|
|
226
210
|
const instanceConfig = {
|
|
227
211
|
useTemplate,
|
|
@@ -234,6 +218,7 @@ exports.create = async ctx => {
|
|
|
234
218
|
const instance = await createInstance(instanceConfig)
|
|
235
219
|
const appId = instance._id
|
|
236
220
|
|
|
221
|
+
const url = await getAppUrlIfNotInUse(ctx)
|
|
237
222
|
const db = new CouchDB(appId)
|
|
238
223
|
let _rev
|
|
239
224
|
try {
|
|
@@ -250,7 +235,7 @@ exports.create = async ctx => {
|
|
|
250
235
|
type: "app",
|
|
251
236
|
version: packageJson.version,
|
|
252
237
|
componentLibraries: ["@budibase/standard-components"],
|
|
253
|
-
name: name,
|
|
238
|
+
name: ctx.request.body.name,
|
|
254
239
|
url: url,
|
|
255
240
|
template: ctx.request.body.template,
|
|
256
241
|
instance: instance,
|
|
@@ -277,22 +262,8 @@ exports.create = async ctx => {
|
|
|
277
262
|
ctx.body = newApplication
|
|
278
263
|
}
|
|
279
264
|
|
|
280
|
-
// This endpoint currently operates as a PATCH rather than a PUT
|
|
281
|
-
// Thus name and url fields are handled only if present
|
|
282
265
|
exports.update = async ctx => {
|
|
283
|
-
const
|
|
284
|
-
// validation
|
|
285
|
-
const name = ctx.request.body.name
|
|
286
|
-
if (name) {
|
|
287
|
-
checkAppName(ctx, apps, name, ctx.params.appId)
|
|
288
|
-
}
|
|
289
|
-
const url = await getAppUrl(ctx)
|
|
290
|
-
if (url) {
|
|
291
|
-
checkAppUrl(ctx, apps, url, ctx.params.appId)
|
|
292
|
-
ctx.request.body.url = url
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
const data = await updateAppPackage(ctx.request.body, ctx.params.appId)
|
|
266
|
+
const data = await updateAppPackage(ctx, ctx.request.body, ctx.params.appId)
|
|
296
267
|
ctx.status = 200
|
|
297
268
|
ctx.body = data
|
|
298
269
|
}
|
|
@@ -314,7 +285,7 @@ exports.updateClient = async ctx => {
|
|
|
314
285
|
version: packageJson.version,
|
|
315
286
|
revertableVersion: currentVersion,
|
|
316
287
|
}
|
|
317
|
-
const data = await updateAppPackage(appPackageUpdates, ctx.params.appId)
|
|
288
|
+
const data = await updateAppPackage(ctx, appPackageUpdates, ctx.params.appId)
|
|
318
289
|
ctx.status = 200
|
|
319
290
|
ctx.body = data
|
|
320
291
|
}
|
|
@@ -337,7 +308,7 @@ exports.revertClient = async ctx => {
|
|
|
337
308
|
version: application.revertableVersion,
|
|
338
309
|
revertableVersion: null,
|
|
339
310
|
}
|
|
340
|
-
const data = await updateAppPackage(appPackageUpdates, ctx.params.appId)
|
|
311
|
+
const data = await updateAppPackage(ctx, appPackageUpdates, ctx.params.appId)
|
|
341
312
|
ctx.status = 200
|
|
342
313
|
ctx.body = data
|
|
343
314
|
}
|
|
@@ -410,11 +381,12 @@ exports.sync = async (ctx, next) => {
|
|
|
410
381
|
}
|
|
411
382
|
}
|
|
412
383
|
|
|
413
|
-
const updateAppPackage = async (appPackage, appId) => {
|
|
384
|
+
const updateAppPackage = async (ctx, appPackage, appId) => {
|
|
385
|
+
const url = await getAppUrlIfNotInUse(ctx)
|
|
414
386
|
const db = new CouchDB(appId)
|
|
415
387
|
const application = await db.get(DocumentTypes.APP_METADATA)
|
|
416
388
|
|
|
417
|
-
const newAppPackage = { ...application, ...appPackage }
|
|
389
|
+
const newAppPackage = { ...application, ...appPackage, url }
|
|
418
390
|
if (appPackage._rev !== application._rev) {
|
|
419
391
|
newAppPackage._rev = application._rev
|
|
420
392
|
}
|
|
@@ -38,13 +38,6 @@ exports.fetch = async function (ctx) {
|
|
|
38
38
|
)
|
|
39
39
|
).rows.map(row => row.doc)
|
|
40
40
|
|
|
41
|
-
for (let datasource of datasources) {
|
|
42
|
-
if (datasource.config && datasource.config.auth) {
|
|
43
|
-
// strip secrets from response so they don't show in the network request
|
|
44
|
-
delete datasource.config.auth
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
41
|
ctx.body = [bbInternalDb, ...datasources]
|
|
49
42
|
}
|
|
50
43
|
|
|
@@ -101,13 +94,8 @@ exports.update = async function (ctx) {
|
|
|
101
94
|
const db = new CouchDB(ctx.appId)
|
|
102
95
|
const datasourceId = ctx.params.datasourceId
|
|
103
96
|
let datasource = await db.get(datasourceId)
|
|
104
|
-
const auth = datasource.config.auth
|
|
105
97
|
await invalidateVariables(datasource, ctx.request.body)
|
|
106
98
|
datasource = { ...datasource, ...ctx.request.body }
|
|
107
|
-
if (auth && !ctx.request.body.auth) {
|
|
108
|
-
// don't strip auth config from DB
|
|
109
|
-
datasource.config.auth = auth
|
|
110
|
-
}
|
|
111
99
|
|
|
112
100
|
const response = await db.put(datasource)
|
|
113
101
|
datasource._rev = response.rev
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const CouchDB = require("../../db")
|
|
2
|
+
const { getDeployedApps } = require("../../utilities/workerRequests")
|
|
3
|
+
const { getScopedConfig } = require("@budibase/backend-core/db")
|
|
4
|
+
const { Configs } = require("@budibase/backend-core/constants")
|
|
5
|
+
const { checkSlashesInUrl } = require("../../utilities")
|
|
6
|
+
|
|
7
|
+
exports.fetchUrls = async ctx => {
|
|
8
|
+
const appId = ctx.appId
|
|
9
|
+
const db = new CouchDB(appId)
|
|
10
|
+
const settings = await getScopedConfig(db, { type: Configs.SETTINGS })
|
|
11
|
+
let appUrl = "http://localhost:10000/app"
|
|
12
|
+
if (settings && settings["platformUrl"]) {
|
|
13
|
+
appUrl = checkSlashesInUrl(`${settings["platformUrl"]}/app`)
|
|
14
|
+
}
|
|
15
|
+
ctx.body = {
|
|
16
|
+
app: appUrl,
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
exports.getDeployedApps = async ctx => {
|
|
21
|
+
ctx.body = await getDeployedApps()
|
|
22
|
+
}
|
|
@@ -525,7 +525,7 @@ module External {
|
|
|
525
525
|
const linkTable = this.getTable(tableId)
|
|
526
526
|
// @ts-ignore
|
|
527
527
|
const linkPrimary = linkTable.primary[0]
|
|
528
|
-
const rows = related[key]
|
|
528
|
+
const rows = related[key]?.rows || []
|
|
529
529
|
const found = rows.find(
|
|
530
530
|
(row: { [key: string]: any }) =>
|
|
531
531
|
row[linkPrimary] === relationship.id ||
|
|
@@ -58,16 +58,22 @@ exports.validate = async ({ appId, tableId, row, table }) => {
|
|
|
58
58
|
let res
|
|
59
59
|
|
|
60
60
|
// Validate.js doesn't seem to handle array
|
|
61
|
-
if (type === FieldTypes.ARRAY
|
|
62
|
-
|
|
61
|
+
if (type === FieldTypes.ARRAY) {
|
|
62
|
+
const hasValues =
|
|
63
|
+
Array.isArray(row[fieldName]) && row[fieldName].length > 0
|
|
64
|
+
|
|
65
|
+
// Check values are valid if values are specified
|
|
66
|
+
if (hasValues) {
|
|
63
67
|
row[fieldName].map(val => {
|
|
64
68
|
if (!constraints.inclusion.includes(val)) {
|
|
65
|
-
errors[fieldName] = "
|
|
69
|
+
errors[fieldName] = "Value not in list"
|
|
66
70
|
}
|
|
67
71
|
})
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Check for required constraint
|
|
75
|
+
if (constraints.presence === true && !hasValues) {
|
|
76
|
+
errors[fieldName] = "Required field"
|
|
71
77
|
}
|
|
72
78
|
} else if (type === FieldTypes.JSON && typeof row[fieldName] === "string") {
|
|
73
79
|
// this should only happen if there is an error
|
|
@@ -5,7 +5,7 @@ const { resolve, join } = require("../../../utilities/centralPath")
|
|
|
5
5
|
const uuid = require("uuid")
|
|
6
6
|
const { ObjectStoreBuckets } = require("../../../constants")
|
|
7
7
|
const { processString } = require("@budibase/string-templates")
|
|
8
|
-
const {
|
|
8
|
+
const { getDeployedApps } = require("../../../utilities/workerRequests")
|
|
9
9
|
const CouchDB = require("../../../db")
|
|
10
10
|
const {
|
|
11
11
|
loadHandlebarsFile,
|
|
@@ -17,8 +17,6 @@ const { clientLibraryPath } = require("../../../utilities")
|
|
|
17
17
|
const { upload } = require("../../../utilities/fileSystem")
|
|
18
18
|
const { attachmentsRelativeURL } = require("../../../utilities")
|
|
19
19
|
const { DocumentTypes } = require("../../../db/utils")
|
|
20
|
-
const AWS = require("aws-sdk")
|
|
21
|
-
const AWS_REGION = env.AWS_REGION ? env.AWS_REGION : "eu-west-1"
|
|
22
20
|
|
|
23
21
|
async function prepareUpload({ s3Key, bucket, metadata, file }) {
|
|
24
22
|
const response = await upload({
|
|
@@ -39,18 +37,12 @@ async function prepareUpload({ s3Key, bucket, metadata, file }) {
|
|
|
39
37
|
}
|
|
40
38
|
}
|
|
41
39
|
|
|
42
|
-
async function
|
|
43
|
-
// the "appId" component of the URL
|
|
40
|
+
async function checkForSelfHostedURL(ctx) {
|
|
41
|
+
// the "appId" component of the URL may actually be a specific self hosted URL
|
|
44
42
|
let possibleAppUrl = `/${encodeURI(ctx.params.appId).toLowerCase()}`
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const app = apps.filter(
|
|
49
|
-
a => a.url && a.url.toLowerCase() === possibleAppUrl
|
|
50
|
-
)[0]
|
|
51
|
-
|
|
52
|
-
if (app && app.appId) {
|
|
53
|
-
return app.appId
|
|
43
|
+
const apps = await getDeployedApps()
|
|
44
|
+
if (apps[possibleAppUrl] && apps[possibleAppUrl].appId) {
|
|
45
|
+
return apps[possibleAppUrl].appId
|
|
54
46
|
} else {
|
|
55
47
|
return ctx.params.appId
|
|
56
48
|
}
|
|
@@ -83,7 +75,10 @@ exports.uploadFile = async function (ctx) {
|
|
|
83
75
|
}
|
|
84
76
|
|
|
85
77
|
exports.serveApp = async function (ctx) {
|
|
86
|
-
let appId =
|
|
78
|
+
let appId = ctx.params.appId
|
|
79
|
+
if (env.SELF_HOSTED) {
|
|
80
|
+
appId = await checkForSelfHostedURL(ctx)
|
|
81
|
+
}
|
|
87
82
|
const App = require("./templates/BudibaseApp.svelte").default
|
|
88
83
|
const db = new CouchDB(appId, { skip_setup: true })
|
|
89
84
|
const appInfo = await db.get(DocumentTypes.APP_METADATA)
|
|
@@ -109,51 +104,3 @@ exports.serveClientLibrary = async function (ctx) {
|
|
|
109
104
|
root: join(NODE_MODULES_PATH, "@budibase", "client", "dist"),
|
|
110
105
|
})
|
|
111
106
|
}
|
|
112
|
-
|
|
113
|
-
exports.getSignedUploadURL = async function (ctx) {
|
|
114
|
-
const database = new CouchDB(ctx.appId)
|
|
115
|
-
|
|
116
|
-
// Ensure datasource is valid
|
|
117
|
-
let datasource
|
|
118
|
-
try {
|
|
119
|
-
const { datasourceId } = ctx.params
|
|
120
|
-
datasource = await database.get(datasourceId)
|
|
121
|
-
if (!datasource) {
|
|
122
|
-
ctx.throw(400, "The specified datasource could not be found")
|
|
123
|
-
}
|
|
124
|
-
} catch (error) {
|
|
125
|
-
ctx.throw(400, "The specified datasource could not be found")
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Ensure we aren't using a custom endpoint
|
|
129
|
-
if (datasource?.config?.endpoint) {
|
|
130
|
-
ctx.throw(400, "S3 datasources with custom endpoints are not supported")
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// Determine type of datasource and generate signed URL
|
|
134
|
-
let signedUrl
|
|
135
|
-
let publicUrl
|
|
136
|
-
if (datasource.source === "S3") {
|
|
137
|
-
const { bucket, key } = ctx.request.body || {}
|
|
138
|
-
if (!bucket || !key) {
|
|
139
|
-
ctx.throw(400, "bucket and key values are required")
|
|
140
|
-
return
|
|
141
|
-
}
|
|
142
|
-
try {
|
|
143
|
-
const s3 = new AWS.S3({
|
|
144
|
-
region: AWS_REGION,
|
|
145
|
-
accessKeyId: datasource?.config?.accessKeyId,
|
|
146
|
-
secretAccessKey: datasource?.config?.secretAccessKey,
|
|
147
|
-
apiVersion: "2006-03-01",
|
|
148
|
-
signatureVersion: "v4",
|
|
149
|
-
})
|
|
150
|
-
const params = { Bucket: bucket, Key: key }
|
|
151
|
-
signedUrl = s3.getSignedUrl("putObject", params)
|
|
152
|
-
publicUrl = `https://${bucket}.s3.${AWS_REGION}.amazonaws.com/${key}`
|
|
153
|
-
} catch (error) {
|
|
154
|
-
ctx.throw(400, error)
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
ctx.body = { signedUrl, publicUrl }
|
|
159
|
-
}
|
|
@@ -2,7 +2,7 @@ const CouchDB = require("../../../db")
|
|
|
2
2
|
const internal = require("./internal")
|
|
3
3
|
const external = require("./external")
|
|
4
4
|
const csvParser = require("../../../utilities/csvParser")
|
|
5
|
-
const { isExternalTable
|
|
5
|
+
const { isExternalTable } = require("../../../integrations/utils")
|
|
6
6
|
const {
|
|
7
7
|
getTableParams,
|
|
8
8
|
getDatasourceParams,
|
|
@@ -32,8 +32,8 @@ exports.fetch = async function (ctx) {
|
|
|
32
32
|
})
|
|
33
33
|
)
|
|
34
34
|
|
|
35
|
-
const internal = internalTables.rows.map(
|
|
36
|
-
...
|
|
35
|
+
const internal = internalTables.rows.map(row => ({
|
|
36
|
+
...row.doc,
|
|
37
37
|
type: "internal",
|
|
38
38
|
sourceId: BudibaseInternalDB._id,
|
|
39
39
|
}))
|
|
@@ -44,18 +44,12 @@ exports.fetch = async function (ctx) {
|
|
|
44
44
|
})
|
|
45
45
|
)
|
|
46
46
|
|
|
47
|
-
const external = externalTables.rows.flatMap(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
sourceId: tableDoc.doc._id,
|
|
54
|
-
sql: isSQL(tableDoc.doc),
|
|
55
|
-
}))
|
|
56
|
-
} else {
|
|
57
|
-
return []
|
|
58
|
-
}
|
|
47
|
+
const external = externalTables.rows.flatMap(row => {
|
|
48
|
+
return Object.values(row.doc.entities || {}).map(entity => ({
|
|
49
|
+
...entity,
|
|
50
|
+
type: "external",
|
|
51
|
+
sourceId: row.doc._id,
|
|
52
|
+
}))
|
|
59
53
|
})
|
|
60
54
|
|
|
61
55
|
ctx.body = [...internal, ...external]
|
|
@@ -8,7 +8,6 @@ const {
|
|
|
8
8
|
getTable,
|
|
9
9
|
handleDataImport,
|
|
10
10
|
} = require("./utils")
|
|
11
|
-
const usageQuota = require("../../../utilities/usageQuota")
|
|
12
11
|
|
|
13
12
|
exports.save = async function (ctx) {
|
|
14
13
|
const appId = ctx.appId
|
|
@@ -120,7 +119,6 @@ exports.destroy = async function (ctx) {
|
|
|
120
119
|
})
|
|
121
120
|
)
|
|
122
121
|
await db.bulkDocs(rows.rows.map(row => ({ ...row.doc, _deleted: true })))
|
|
123
|
-
await usageQuota.update(usageQuota.Properties.ROW, -rows.rows.length)
|
|
124
122
|
|
|
125
123
|
// update linked rows
|
|
126
124
|
await linkRows.updateLinks({
|