@budibase/server 1.0.46-alpha.2 → 1.0.46-alpha.3
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.89280093.js → index.6eae2fa0.js} +28 -28
- package/builder/index.html +1 -1
- package/coverage/clover.xml +1412 -1236
- package/coverage/coverage-final.json +89 -83
- 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 +90 -90
- 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 +1 -1
- package/coverage/lcov-report/api/controllers/datasource.js.html +16 -16
- 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 +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 +1 -1
- 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 +25 -25
- 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 +16 -16
- package/coverage/lcov-report/api/controllers/table/index.js.html +25 -25
- package/coverage/lcov-report/api/controllers/table/internal.js.html +40 -34
- package/coverage/lcov-report/api/controllers/table/utils.js.html +76 -61
- 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 +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 +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 +13 -19
- package/coverage/lcov-report/automations/steps/delay.js.html +4 -4
- package/coverage/lcov-report/automations/steps/deleteRow.js.html +11 -20
- 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 +1 -1
- package/coverage/lcov-report/constants/index.js.html +22 -22
- 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 +83 -83
- 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 +68 -38
- 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 +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 +275 -41
- package/coverage/lcov-report/middleware/utils.js.html +1 -1
- package/coverage/lcov-report/migrations/usageQuotas/index.html +141 -0
- package/coverage/lcov-report/migrations/usageQuotas/index.js.html +152 -0
- package/coverage/lcov-report/migrations/usageQuotas/syncApps.js.html +134 -0
- package/coverage/lcov-report/migrations/usageQuotas/syncRows.js.html +143 -0
- package/coverage/lcov-report/threads/automation.js.html +1 -1
- package/coverage/lcov-report/threads/index.html +1 -1
- package/coverage/lcov-report/threads/index.js.html +10 -10
- package/coverage/lcov-report/threads/query.js.html +1 -1
- 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 +14 -14
- package/coverage/lcov-report/utilities/index.html +1 -1
- 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/usageQuota/index.html +141 -0
- package/coverage/lcov-report/utilities/usageQuota/index.js.html +356 -0
- package/coverage/lcov-report/utilities/usageQuota/rows.js.html +302 -0
- package/coverage/lcov-report/utilities/usageQuota/usageQuoteReset.js.html +134 -0
- package/coverage/lcov-report/utilities/users.js.html +5 -5
- package/coverage/lcov-report/utilities/workerRequests.js.html +31 -31
- package/coverage/lcov.info +1900 -1602
- package/dist/api/controllers/table/internal.js +2 -0
- package/dist/api/controllers/table/utils.js +5 -0
- package/dist/automations/steps/createRow.js +2 -4
- package/dist/automations/steps/deleteRow.js +1 -4
- package/dist/environment.js +1 -0
- package/dist/middleware/usageQuota.js +82 -13
- package/dist/migrations/usageQuotas/index.js +24 -0
- package/dist/migrations/usageQuotas/syncApps.js +26 -0
- package/dist/migrations/usageQuotas/syncRows.js +29 -0
- package/dist/package.json +4 -4
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utilities/{usageQuota.js → usageQuota/index.js} +44 -31
- package/dist/utilities/usageQuota/rows.js +77 -0
- package/dist/utilities/usageQuota/usageQuoteReset.js +16 -0
- package/package.json +5 -5
- package/src/api/controllers/table/internal.js +2 -0
- package/src/api/controllers/table/utils.js +5 -0
- package/src/automations/steps/createRow.js +2 -4
- package/src/automations/steps/deleteRow.js +1 -4
- package/src/environment.js +1 -0
- package/src/middleware/tests/usageQuota.spec.js +18 -24
- package/src/middleware/usageQuota.js +93 -15
- package/src/migrations/tests/usageQuotas/index.spec.js +27 -0
- package/src/migrations/tests/usageQuotas/syncApps.spec.js +37 -0
- package/src/migrations/tests/usageQuotas/syncRows.spec.js +43 -0
- package/src/migrations/usageQuotas/index.js +24 -0
- package/src/migrations/usageQuotas/syncApps.js +18 -0
- package/src/migrations/usageQuotas/syncRows.js +21 -0
- package/src/utilities/tests/usageQuota/usageQuota.spec.js +72 -0
- package/src/utilities/usageQuota/index.js +92 -0
- package/src/utilities/usageQuota/rows.js +74 -0
- package/src/utilities/usageQuota/usageQuoteReset.js +18 -0
- package/src/utilities/usageQuota.js +0 -73
|
@@ -8,12 +8,24 @@ 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 } = require("@budibase/backend-core/tenancy");
|
|
11
|
+
const env = require("../../environment");
|
|
12
|
+
const { getGlobalDB, getTenantId } = require("@budibase/backend-core/tenancy");
|
|
13
13
|
const { StaticDatabases, generateNewUsageQuotaDoc, } = require("@budibase/backend-core/db");
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
exports.useQuotas = () => {
|
|
15
|
+
// check if quotas are enabled
|
|
16
|
+
if (env.USE_QUOTAS) {
|
|
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
|
+
};
|
|
17
29
|
exports.Properties = {
|
|
18
30
|
ROW: "rows",
|
|
19
31
|
UPLOAD: "storage",
|
|
@@ -21,21 +33,21 @@ exports.Properties = {
|
|
|
21
33
|
USER: "users",
|
|
22
34
|
AUTOMATION: "automationRuns",
|
|
23
35
|
APPS: "apps",
|
|
24
|
-
EMAILS: "emails",
|
|
36
|
+
EMAILS: "emails", // doesn't work yet
|
|
25
37
|
};
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
38
|
+
exports.getUsageQuotaDoc = (db) => __awaiter(void 0, void 0, void 0, function* () {
|
|
39
|
+
let quota;
|
|
40
|
+
try {
|
|
41
|
+
quota = yield db.get(StaticDatabases.GLOBAL.docs.usageQuota);
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
// doc doesn't exist. Create it
|
|
45
|
+
quota = generateNewUsageQuotaDoc();
|
|
46
|
+
const response = yield db.put(quota);
|
|
47
|
+
quota._rev = response.rev;
|
|
48
|
+
}
|
|
49
|
+
return quota;
|
|
50
|
+
});
|
|
39
51
|
/**
|
|
40
52
|
* Given a specified tenantId this will add to the usage object for the specified property.
|
|
41
53
|
* @param {string} property The property which is to be added to (within the nested usageQuota object).
|
|
@@ -43,27 +55,28 @@ function getUsageQuotaDoc(db) {
|
|
|
43
55
|
* @returns {Promise<void>} When this completes the API key will now be up to date - the quota period may have
|
|
44
56
|
* also been reset after this call.
|
|
45
57
|
*/
|
|
46
|
-
exports.update = (property, usage) => __awaiter(void 0, void 0, void 0, function* () {
|
|
47
|
-
if (!
|
|
58
|
+
exports.update = (property, usage, opts = { dryRun: false }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
59
|
+
if (!exports.useQuotas()) {
|
|
48
60
|
return;
|
|
49
61
|
}
|
|
50
62
|
try {
|
|
51
63
|
const db = getGlobalDB();
|
|
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
|
-
}
|
|
64
|
+
const quota = yield exports.getUsageQuotaDoc(db);
|
|
60
65
|
// increment the quota
|
|
61
66
|
quota.usageQuota[property] += usage;
|
|
62
|
-
if (quota.usageQuota[property] > quota.usageLimits[property]
|
|
67
|
+
if (quota.usageQuota[property] > quota.usageLimits[property] &&
|
|
68
|
+
usage > 0 // allow for decrementing usage when the quota is already exceeded
|
|
69
|
+
) {
|
|
63
70
|
throw new Error(`You have exceeded your usage quota of ${quota.usageLimits[property]} ${property}.`);
|
|
64
71
|
}
|
|
72
|
+
if (quota.usageQuota[property] < 0) {
|
|
73
|
+
// never go negative if the quota has previously been exceeded
|
|
74
|
+
quota.usageQuota[property] = 0;
|
|
75
|
+
}
|
|
65
76
|
// update the usage quotas
|
|
66
|
-
|
|
77
|
+
if (!opts.dryRun) {
|
|
78
|
+
yield db.put(quota);
|
|
79
|
+
}
|
|
67
80
|
}
|
|
68
81
|
catch (err) {
|
|
69
82
|
console.error(`Error updating usage quotas for ${property}`, err);
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
const { getRowParams, USER_METDATA_PREFIX } = require("../../db/utils");
|
|
12
|
+
const CouchDB = require("../../db");
|
|
13
|
+
const { isDevAppID, getDevelopmentAppID } = require("@budibase/backend-core/db");
|
|
14
|
+
const ROW_EXCLUSIONS = [USER_METDATA_PREFIX];
|
|
15
|
+
const getAppPairs = appIds => {
|
|
16
|
+
// collect the app ids into dev / prod pairs
|
|
17
|
+
// keyed by the dev app id
|
|
18
|
+
const pairs = {};
|
|
19
|
+
for (let appId of appIds) {
|
|
20
|
+
const devId = getDevelopmentAppID(appId);
|
|
21
|
+
if (!pairs[devId]) {
|
|
22
|
+
pairs[devId] = {};
|
|
23
|
+
}
|
|
24
|
+
if (isDevAppID(appId)) {
|
|
25
|
+
pairs[devId].devId = appId;
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
pairs[devId].prodId = appId;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return pairs;
|
|
32
|
+
};
|
|
33
|
+
const getAppRows = (appId) => __awaiter(void 0, void 0, void 0, function* () {
|
|
34
|
+
const appDb = new CouchDB(appId);
|
|
35
|
+
const response = yield appDb.allDocs(getRowParams(null, null, {
|
|
36
|
+
include_docs: false,
|
|
37
|
+
}));
|
|
38
|
+
return response.rows
|
|
39
|
+
.map(r => r.id)
|
|
40
|
+
.filter(id => {
|
|
41
|
+
for (let exclusion of ROW_EXCLUSIONS) {
|
|
42
|
+
if (id.startsWith(exclusion)) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return true;
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
/**
|
|
50
|
+
* Return a set of all rows in the given app ids.
|
|
51
|
+
* The returned rows will be unique on a per dev/prod app basis.
|
|
52
|
+
* Rows duplicates may exist across apps due to data import so they are not filtered out.
|
|
53
|
+
*/
|
|
54
|
+
exports.getUniqueRows = (appIds) => __awaiter(void 0, void 0, void 0, function* () {
|
|
55
|
+
let uniqueRows = [];
|
|
56
|
+
const pairs = getAppPairs(appIds);
|
|
57
|
+
for (let pair of Object.values(pairs)) {
|
|
58
|
+
let appRows = [];
|
|
59
|
+
for (let appId of [pair.devId, pair.prodId]) {
|
|
60
|
+
if (!appId) {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
appRows.push(yield getAppRows(appId));
|
|
65
|
+
}
|
|
66
|
+
catch (e) {
|
|
67
|
+
console.error(e);
|
|
68
|
+
// don't error out if we can't count the app rows, just continue
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// ensure uniqueness on a per app pair basis
|
|
72
|
+
// this can't be done on all rows because app import results in
|
|
73
|
+
// duplicate row ids across apps
|
|
74
|
+
uniqueRows = uniqueRows.concat(...new Set(appRows));
|
|
75
|
+
}
|
|
76
|
+
return uniqueRows;
|
|
77
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// UNUSED CODE
|
|
3
|
+
// Preserved for future use
|
|
4
|
+
/* eslint-disable no-unused-vars */
|
|
5
|
+
function getNewQuotaReset() {
|
|
6
|
+
return Date.now() + 2592000000;
|
|
7
|
+
}
|
|
8
|
+
function resetQuotasIfRequired(quota) {
|
|
9
|
+
// Check if the quota needs reset
|
|
10
|
+
if (Date.now() >= quota.quotaReset) {
|
|
11
|
+
quota.quotaReset = getNewQuotaReset();
|
|
12
|
+
for (let prop of Object.keys(quota.usageQuota)) {
|
|
13
|
+
quota.usageQuota[prop] = 0;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
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.46-alpha.
|
|
4
|
+
"version": "1.0.46-alpha.3",
|
|
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.46-alpha.
|
|
74
|
-
"@budibase/client": "^1.0.46-alpha.
|
|
75
|
-
"@budibase/string-templates": "^1.0.46-alpha.
|
|
73
|
+
"@budibase/backend-core": "^1.0.46-alpha.3",
|
|
74
|
+
"@budibase/client": "^1.0.46-alpha.3",
|
|
75
|
+
"@budibase/string-templates": "^1.0.46-alpha.3",
|
|
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": "b10f29e52b94b0c2c0c61a7a1ad7669fcd37d473"
|
|
169
169
|
}
|
|
@@ -8,6 +8,7 @@ const {
|
|
|
8
8
|
getTable,
|
|
9
9
|
handleDataImport,
|
|
10
10
|
} = require("./utils")
|
|
11
|
+
const usageQuota = require("../../../utilities/usageQuota")
|
|
11
12
|
|
|
12
13
|
exports.save = async function (ctx) {
|
|
13
14
|
const appId = ctx.appId
|
|
@@ -119,6 +120,7 @@ exports.destroy = async function (ctx) {
|
|
|
119
120
|
})
|
|
120
121
|
)
|
|
121
122
|
await db.bulkDocs(rows.rows.map(row => ({ ...row.doc, _deleted: true })))
|
|
123
|
+
await usageQuota.update(usageQuota.Properties.ROW, -rows.rows.length)
|
|
122
124
|
|
|
123
125
|
// update linked rows
|
|
124
126
|
await linkRows.updateLinks({
|
|
@@ -16,6 +16,7 @@ const {
|
|
|
16
16
|
} = require("../../../integrations/utils")
|
|
17
17
|
const { getViews, saveView } = require("../view/utils")
|
|
18
18
|
const viewTemplate = require("../view/viewBuilder")
|
|
19
|
+
const usageQuota = require("../../../utilities/usageQuota")
|
|
19
20
|
|
|
20
21
|
exports.checkForColumnUpdates = async (db, oldTable, updatedTable) => {
|
|
21
22
|
let updatedRows = []
|
|
@@ -112,7 +113,11 @@ exports.handleDataImport = async (appId, user, table, dataImport) => {
|
|
|
112
113
|
finalData.push(row)
|
|
113
114
|
}
|
|
114
115
|
|
|
116
|
+
await usageQuota.update(usageQuota.Properties.ROW, finalData.length, {
|
|
117
|
+
dryRun: true,
|
|
118
|
+
})
|
|
115
119
|
await db.bulkDocs(finalData)
|
|
120
|
+
await usageQuota.update(usageQuota.Properties.ROW, finalData.length)
|
|
116
121
|
let response = await db.put(table)
|
|
117
122
|
table._rev = response._rev
|
|
118
123
|
return table
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const rowController = require("../../api/controllers/row")
|
|
2
2
|
const automationUtils = require("../automationUtils")
|
|
3
|
-
const env = require("../../environment")
|
|
4
3
|
const usage = require("../../utilities/usageQuota")
|
|
5
4
|
const { buildCtx } = require("./utils")
|
|
6
5
|
|
|
@@ -83,10 +82,9 @@ exports.run = async function ({ inputs, appId, emitter }) {
|
|
|
83
82
|
inputs.row.tableId,
|
|
84
83
|
inputs.row
|
|
85
84
|
)
|
|
86
|
-
|
|
87
|
-
await usage.update(usage.Properties.ROW, 1)
|
|
88
|
-
}
|
|
85
|
+
await usage.update(usage.Properties.ROW, 1, { dryRun: true })
|
|
89
86
|
await rowController.save(ctx)
|
|
87
|
+
await usage.update(usage.Properties.ROW, 1)
|
|
90
88
|
return {
|
|
91
89
|
row: inputs.row,
|
|
92
90
|
response: ctx.body,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const rowController = require("../../api/controllers/row")
|
|
2
|
-
const env = require("../../environment")
|
|
3
2
|
const usage = require("../../utilities/usageQuota")
|
|
4
3
|
const { buildCtx } = require("./utils")
|
|
5
4
|
const automationUtils = require("../automationUtils")
|
|
@@ -74,9 +73,7 @@ exports.run = async function ({ inputs, appId, emitter }) {
|
|
|
74
73
|
})
|
|
75
74
|
|
|
76
75
|
try {
|
|
77
|
-
|
|
78
|
-
await usage.update(usage.Properties.ROW, -1)
|
|
79
|
-
}
|
|
76
|
+
await usage.update(usage.Properties.ROW, -1)
|
|
80
77
|
await rowController.destroy(ctx)
|
|
81
78
|
return {
|
|
82
79
|
response: ctx.body,
|
package/src/environment.js
CHANGED
|
@@ -38,6 +38,7 @@ module.exports = {
|
|
|
38
38
|
MINIO_ACCESS_KEY: process.env.MINIO_ACCESS_KEY,
|
|
39
39
|
MINIO_SECRET_KEY: process.env.MINIO_SECRET_KEY,
|
|
40
40
|
USE_QUOTAS: process.env.USE_QUOTAS,
|
|
41
|
+
EXCLUDE_QUOTAS_TENANTS: process.env.EXCLUDE_QUOTAS_TENANTS,
|
|
41
42
|
REDIS_URL: process.env.REDIS_URL,
|
|
42
43
|
REDIS_PASSWORD: process.env.REDIS_PASSWORD,
|
|
43
44
|
INTERNAL_API_KEY: process.env.INTERNAL_API_KEY,
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
jest.mock("../../db")
|
|
2
2
|
jest.mock("../../utilities/usageQuota")
|
|
3
|
-
jest.mock("../../environment", () => ({
|
|
4
|
-
isTest: () => true,
|
|
5
|
-
isProd: () => false,
|
|
6
|
-
isDev: () => true,
|
|
7
|
-
_set: () => {},
|
|
8
|
-
}))
|
|
9
3
|
jest.mock("@budibase/backend-core/tenancy", () => ({
|
|
10
4
|
getTenantId: () => "testing123"
|
|
11
5
|
}))
|
|
@@ -29,9 +23,10 @@ class TestConfiguration {
|
|
|
29
23
|
},
|
|
30
24
|
req: {
|
|
31
25
|
method: "POST",
|
|
32
|
-
url: "/
|
|
26
|
+
url: "/applications"
|
|
33
27
|
}
|
|
34
28
|
}
|
|
29
|
+
usageQuota.useQuotas = () => true
|
|
35
30
|
}
|
|
36
31
|
|
|
37
32
|
executeMiddleware() {
|
|
@@ -113,7 +108,6 @@ describe("usageQuota middleware", () => {
|
|
|
113
108
|
|
|
114
109
|
it("calculates and persists the correct usage quota for the relevant action", async () => {
|
|
115
110
|
config.setUrl("/rows")
|
|
116
|
-
config.setProd(true)
|
|
117
111
|
|
|
118
112
|
await config.executeMiddleware()
|
|
119
113
|
|
|
@@ -121,20 +115,20 @@ describe("usageQuota middleware", () => {
|
|
|
121
115
|
expect(config.next).toHaveBeenCalled()
|
|
122
116
|
})
|
|
123
117
|
|
|
124
|
-
it("calculates the correct file size from a file upload call and adds it to quota", async () => {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
})
|
|
118
|
+
// it("calculates the correct file size from a file upload call and adds it to quota", async () => {
|
|
119
|
+
// config.setUrl("/upload")
|
|
120
|
+
// config.setProd(true)
|
|
121
|
+
// config.setFiles([
|
|
122
|
+
// {
|
|
123
|
+
// size: 100
|
|
124
|
+
// },
|
|
125
|
+
// {
|
|
126
|
+
// size: 10000
|
|
127
|
+
// },
|
|
128
|
+
// ])
|
|
129
|
+
// await config.executeMiddleware()
|
|
130
|
+
|
|
131
|
+
// expect(usageQuota.update).toHaveBeenCalledWith("storage", 10100)
|
|
132
|
+
// expect(config.next).toHaveBeenCalled()
|
|
133
|
+
// })
|
|
140
134
|
})
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
const CouchDB = require("../db")
|
|
2
2
|
const usageQuota = require("../utilities/usageQuota")
|
|
3
|
-
const
|
|
4
|
-
const { getTenantId } = require("@budibase/backend-core/tenancy")
|
|
3
|
+
const { getUniqueRows } = require("../utilities/usageQuota/rows")
|
|
5
4
|
const {
|
|
6
5
|
isExternalTable,
|
|
7
6
|
isRowId: isExternalRowId,
|
|
8
7
|
} = require("../integrations/utils")
|
|
9
|
-
|
|
10
|
-
// tenants without limits
|
|
11
|
-
const EXCLUDED_TENANTS = ["bb", "default", "bbtest", "bbstaging"]
|
|
8
|
+
const migration = require("../migrations/usageQuotas")
|
|
12
9
|
|
|
13
10
|
// currently only counting new writes and deletes
|
|
14
11
|
const METHOD_MAP = {
|
|
@@ -18,13 +15,13 @@ const METHOD_MAP = {
|
|
|
18
15
|
|
|
19
16
|
const DOMAIN_MAP = {
|
|
20
17
|
rows: usageQuota.Properties.ROW,
|
|
21
|
-
upload: usageQuota.Properties.UPLOAD,
|
|
22
|
-
views: usageQuota.Properties.VIEW,
|
|
23
|
-
users: usageQuota.Properties.USER,
|
|
18
|
+
// upload: usageQuota.Properties.UPLOAD, // doesn't work yet
|
|
19
|
+
// views: usageQuota.Properties.VIEW, // doesn't work yet
|
|
20
|
+
// users: usageQuota.Properties.USER, // doesn't work yet
|
|
24
21
|
applications: usageQuota.Properties.APPS,
|
|
25
22
|
// this will not be updated by endpoint calls
|
|
26
23
|
// instead it will be updated by triggerInfo
|
|
27
|
-
automationRuns: usageQuota.Properties.AUTOMATION,
|
|
24
|
+
// automationRuns: usageQuota.Properties.AUTOMATION, // doesn't work yet
|
|
28
25
|
}
|
|
29
26
|
|
|
30
27
|
function getProperty(url) {
|
|
@@ -36,10 +33,7 @@ function getProperty(url) {
|
|
|
36
33
|
}
|
|
37
34
|
|
|
38
35
|
module.exports = async (ctx, next) => {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
// if in development or a self hosted cloud usage quotas should not be executed
|
|
42
|
-
if (env.isDev() || env.SELF_HOSTED || EXCLUDED_TENANTS.includes(tenantId)) {
|
|
36
|
+
if (!usageQuota.useQuotas()) {
|
|
43
37
|
return next()
|
|
44
38
|
}
|
|
45
39
|
|
|
@@ -80,9 +74,93 @@ module.exports = async (ctx, next) => {
|
|
|
80
74
|
usage = files.map(file => file.size).reduce((total, size) => total + size)
|
|
81
75
|
}
|
|
82
76
|
try {
|
|
83
|
-
await
|
|
84
|
-
|
|
77
|
+
await migration.run()
|
|
78
|
+
await performRequest(ctx, next, property, usage)
|
|
85
79
|
} catch (err) {
|
|
86
80
|
ctx.throw(400, err)
|
|
87
81
|
}
|
|
88
82
|
}
|
|
83
|
+
|
|
84
|
+
const performRequest = async (ctx, next, property, usage) => {
|
|
85
|
+
const usageContext = {
|
|
86
|
+
skipNext: false,
|
|
87
|
+
skipUsage: false,
|
|
88
|
+
[usageQuota.Properties.APPS]: {},
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (usage === -1) {
|
|
92
|
+
if (PRE_DELETE[property]) {
|
|
93
|
+
await PRE_DELETE[property](ctx, usageContext)
|
|
94
|
+
}
|
|
95
|
+
} else {
|
|
96
|
+
if (PRE_CREATE[property]) {
|
|
97
|
+
await PRE_CREATE[property](ctx, usageContext)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// run the request
|
|
102
|
+
if (!usageContext.skipNext) {
|
|
103
|
+
await usageQuota.update(property, usage, { dryRun: true })
|
|
104
|
+
await next()
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (usage === -1) {
|
|
108
|
+
if (POST_DELETE[property]) {
|
|
109
|
+
await POST_DELETE[property](ctx, usageContext)
|
|
110
|
+
}
|
|
111
|
+
} else {
|
|
112
|
+
if (POST_CREATE[property]) {
|
|
113
|
+
await POST_CREATE[property](ctx, usageContext)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// update the usage
|
|
118
|
+
if (!usageContext.skipUsage) {
|
|
119
|
+
await usageQuota.update(property, usage)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const appPreDelete = async (ctx, usageContext) => {
|
|
124
|
+
if (ctx.query.unpublish) {
|
|
125
|
+
// don't run usage decrement for unpublish
|
|
126
|
+
usageContext.skipUsage = true
|
|
127
|
+
return
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// store the row count to delete
|
|
131
|
+
const rows = await getUniqueRows([ctx.appId])
|
|
132
|
+
if (rows.length) {
|
|
133
|
+
usageContext[usageQuota.Properties.APPS] = { rowCount: rows.length }
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const appPostDelete = async (ctx, usageContext) => {
|
|
138
|
+
// delete the app rows from usage
|
|
139
|
+
const rowCount = usageContext[usageQuota.Properties.APPS].rowCount
|
|
140
|
+
if (rowCount) {
|
|
141
|
+
await usageQuota.update(usageQuota.Properties.ROW, -rowCount)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const appPostCreate = async ctx => {
|
|
146
|
+
// app import & template creation
|
|
147
|
+
if (ctx.request.body.useTemplate === "true") {
|
|
148
|
+
const rows = await getUniqueRows([ctx.response.body.appId])
|
|
149
|
+
const rowCount = rows ? rows.length : 0
|
|
150
|
+
await usageQuota.update(usageQuota.Properties.ROW, rowCount)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const PRE_DELETE = {
|
|
155
|
+
[usageQuota.Properties.APPS]: appPreDelete,
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const POST_DELETE = {
|
|
159
|
+
[usageQuota.Properties.APPS]: appPostDelete,
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const PRE_CREATE = {}
|
|
163
|
+
|
|
164
|
+
const POST_CREATE = {
|
|
165
|
+
[usageQuota.Properties.APPS]: appPostCreate,
|
|
166
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const env = require("../../../environment")
|
|
2
|
+
const TestConfig = require("../../../tests/utilities/TestConfiguration")
|
|
3
|
+
|
|
4
|
+
const syncApps = jest.fn()
|
|
5
|
+
const syncRows = jest.fn()
|
|
6
|
+
|
|
7
|
+
jest.mock("../../usageQuotas/syncApps", () => ({ run: syncApps }) )
|
|
8
|
+
jest.mock("../../usageQuotas/syncRows", () => ({ run: syncRows }) )
|
|
9
|
+
|
|
10
|
+
const migrations = require("../../usageQuotas")
|
|
11
|
+
|
|
12
|
+
describe("run", () => {
|
|
13
|
+
let config = new TestConfig(false)
|
|
14
|
+
|
|
15
|
+
beforeEach(async () => {
|
|
16
|
+
await config.init()
|
|
17
|
+
env._set("USE_QUOTAS", 1)
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
afterAll(config.end)
|
|
21
|
+
|
|
22
|
+
it("runs the required migrations", async () => {
|
|
23
|
+
await migrations.run()
|
|
24
|
+
expect(syncApps).toHaveBeenCalledTimes(1)
|
|
25
|
+
expect(syncRows).toHaveBeenCalledTimes(1)
|
|
26
|
+
})
|
|
27
|
+
})
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const { getGlobalDB } = require("@budibase/backend-core/tenancy")
|
|
2
|
+
const TestConfig = require("../../../tests/utilities/TestConfiguration")
|
|
3
|
+
const { getUsageQuotaDoc, update, Properties } = require("../../../utilities/usageQuota")
|
|
4
|
+
const syncApps = require("../../usageQuotas/syncApps")
|
|
5
|
+
const env = require("../../../environment")
|
|
6
|
+
|
|
7
|
+
describe("syncApps", () => {
|
|
8
|
+
let config = new TestConfig(false)
|
|
9
|
+
|
|
10
|
+
beforeEach(async () => {
|
|
11
|
+
await config.init()
|
|
12
|
+
env._set("USE_QUOTAS", 1)
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
afterAll(config.end)
|
|
16
|
+
|
|
17
|
+
it("runs successfully", async () => {
|
|
18
|
+
// create the usage quota doc and mock usages
|
|
19
|
+
const db = getGlobalDB()
|
|
20
|
+
await getUsageQuotaDoc(db)
|
|
21
|
+
await update(Properties.APPS, 3)
|
|
22
|
+
|
|
23
|
+
let usageDoc = await getUsageQuotaDoc(db)
|
|
24
|
+
expect(usageDoc.usageQuota.apps).toEqual(3)
|
|
25
|
+
|
|
26
|
+
// create an extra app to test the migration
|
|
27
|
+
await config.createApp("quota-test")
|
|
28
|
+
|
|
29
|
+
// migrate
|
|
30
|
+
await syncApps.run()
|
|
31
|
+
|
|
32
|
+
// assert the migration worked
|
|
33
|
+
usageDoc = await getUsageQuotaDoc(db)
|
|
34
|
+
expect(usageDoc.usageQuota.apps).toEqual(2)
|
|
35
|
+
})
|
|
36
|
+
})
|
|
37
|
+
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const { getGlobalDB } = require("@budibase/backend-core/tenancy")
|
|
2
|
+
const TestConfig = require("../../../tests/utilities/TestConfiguration")
|
|
3
|
+
const { getUsageQuotaDoc, update, Properties } = require("../../../utilities/usageQuota")
|
|
4
|
+
const syncRows = require("../../usageQuotas/syncRows")
|
|
5
|
+
const env = require("../../../environment")
|
|
6
|
+
|
|
7
|
+
describe("syncRows", () => {
|
|
8
|
+
let config = new TestConfig(false)
|
|
9
|
+
|
|
10
|
+
beforeEach(async () => {
|
|
11
|
+
await config.init()
|
|
12
|
+
env._set("USE_QUOTAS", 1)
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
afterAll(config.end)
|
|
16
|
+
|
|
17
|
+
it("runs successfully", async () => {
|
|
18
|
+
// create the usage quota doc and mock usages
|
|
19
|
+
const db = getGlobalDB()
|
|
20
|
+
await getUsageQuotaDoc(db)
|
|
21
|
+
await update(Properties.ROW, 300)
|
|
22
|
+
|
|
23
|
+
let usageDoc = await getUsageQuotaDoc(db)
|
|
24
|
+
expect(usageDoc.usageQuota.rows).toEqual(300)
|
|
25
|
+
|
|
26
|
+
// app 1
|
|
27
|
+
await config.createTable()
|
|
28
|
+
await config.createRow()
|
|
29
|
+
// app 2
|
|
30
|
+
await config.createApp()
|
|
31
|
+
await config.createTable()
|
|
32
|
+
await config.createRow()
|
|
33
|
+
await config.createRow()
|
|
34
|
+
|
|
35
|
+
// migrate
|
|
36
|
+
await syncRows.run()
|
|
37
|
+
|
|
38
|
+
// assert the migration worked
|
|
39
|
+
usageDoc = await getUsageQuotaDoc(db)
|
|
40
|
+
expect(usageDoc.usageQuota.rows).toEqual(3)
|
|
41
|
+
})
|
|
42
|
+
})
|
|
43
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const {
|
|
2
|
+
MIGRATIONS,
|
|
3
|
+
MIGRATION_DBS,
|
|
4
|
+
migrateIfRequired,
|
|
5
|
+
} = require("@budibase/backend-core/migrations")
|
|
6
|
+
const { useQuotas } = require("../../utilities/usageQuota")
|
|
7
|
+
const syncApps = require("./syncApps")
|
|
8
|
+
const syncRows = require("./syncRows")
|
|
9
|
+
|
|
10
|
+
exports.run = async () => {
|
|
11
|
+
if (!useQuotas()) {
|
|
12
|
+
return
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Jan 2022
|
|
16
|
+
await migrateIfRequired(
|
|
17
|
+
MIGRATION_DBS.GLOBAL_DB,
|
|
18
|
+
MIGRATIONS.QUOTAS_1,
|
|
19
|
+
async () => {
|
|
20
|
+
await syncApps.run()
|
|
21
|
+
await syncRows.run()
|
|
22
|
+
}
|
|
23
|
+
)
|
|
24
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const { getGlobalDB, getTenantId } = require("@budibase/backend-core/tenancy")
|
|
2
|
+
const { getAllApps } = require("@budibase/backend-core/db")
|
|
3
|
+
const CouchDB = require("../../db")
|
|
4
|
+
const { getUsageQuotaDoc } = require("../../utilities/usageQuota")
|
|
5
|
+
|
|
6
|
+
exports.run = async () => {
|
|
7
|
+
const db = getGlobalDB()
|
|
8
|
+
// get app count
|
|
9
|
+
const devApps = await getAllApps(CouchDB, { dev: true })
|
|
10
|
+
const appCount = devApps ? devApps.length : 0
|
|
11
|
+
|
|
12
|
+
// sync app count
|
|
13
|
+
const tenantId = getTenantId()
|
|
14
|
+
console.log(`[Tenant: ${tenantId}] Syncing app count: ${appCount}`)
|
|
15
|
+
const usageDoc = await getUsageQuotaDoc(db)
|
|
16
|
+
usageDoc.usageQuota.apps = appCount
|
|
17
|
+
await db.put(usageDoc)
|
|
18
|
+
}
|