@budibase/server 1.0.46 → 1.0.49-alpha.1
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.ba78c49d.css +1 -0
- package/builder/assets/{index.e9bff1c6.js → index.ed1cf508.js} +237 -234
- package/builder/assets/{vendor.f9faf6ab.js → vendor.d526bfe8.js} +12 -12
- package/builder/index.html +3 -3
- package/coverage/clover.xml +2368 -2016
- package/coverage/coverage-final.json +101 -95
- 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 +210 -126
- package/coverage/lcov-report/api/controllers/auth.js.html +18 -6
- 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 +72 -36
- package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
- package/coverage/lcov-report/api/controllers/index.html +38 -53
- 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 +48 -33
- package/coverage/lcov-report/api/controllers/row/index.js.html +26 -26
- package/coverage/lcov-report/api/controllers/row/internal.js.html +95 -158
- package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +41 -17
- package/coverage/lcov-report/api/controllers/row/staticFormula.js.html +551 -0
- package/coverage/lcov-report/api/controllers/row/utils.js.html +39 -57
- 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/bulkFormula.js.html +629 -0
- package/coverage/lcov-report/api/controllers/table/external.js.html +12 -12
- package/coverage/lcov-report/api/controllers/table/index.html +49 -34
- package/coverage/lcov-report/api/controllers/table/index.js.html +53 -77
- package/coverage/lcov-report/api/controllers/table/internal.js.html +59 -35
- package/coverage/lcov-report/api/controllers/table/utils.js.html +283 -76
- package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
- package/coverage/lcov-report/api/controllers/user.js.html +30 -24
- 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/api/routes/index.html +7 -22
- package/coverage/lcov-report/api/routes/index.js.html +4 -10
- 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 +17 -2
- 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 +11 -11
- package/coverage/lcov-report/constants/index.js.html +68 -32
- 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 +10 -10
- package/coverage/lcov-report/db/linkedRows/index.js.html +38 -41
- 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 +86 -86
- 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 +131 -101
- 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 +166 -64
- 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 +30 -30
- 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 +2 -2
- 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/{api/routes/hosting.js.html → migrations/usageQuotas/syncApps.js.html} +42 -27
- package/coverage/lcov-report/{api/controllers/hosting.js.html → migrations/usageQuotas/syncRows.js.html} +41 -44
- 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 +23 -8
- 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 +27 -27
- package/coverage/lcov-report/utilities/rowProcessor/index.js.html +115 -79
- package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +75 -27
- 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 +39 -108
- package/coverage/lcov.info +3719 -3046
- package/dist/api/controllers/application.js +49 -20
- package/dist/api/controllers/auth.js +4 -0
- package/dist/api/controllers/datasource.js +11 -0
- package/dist/api/controllers/row/ExternalRequest.js +2 -1
- package/dist/api/controllers/row/internal.js +30 -53
- package/dist/api/controllers/row/internalSearch.js +12 -4
- package/dist/api/controllers/row/staticFormula.js +147 -0
- package/dist/api/controllers/row/utils.js +6 -8
- package/dist/api/controllers/static/index.js +59 -10
- package/dist/api/controllers/table/bulkFormula.js +160 -0
- package/dist/api/controllers/table/index.js +12 -9
- package/dist/api/controllers/table/internal.js +9 -0
- package/dist/api/controllers/table/utils.js +56 -14
- package/dist/api/controllers/user.js +2 -0
- package/dist/api/routes/index.js +0 -2
- package/dist/api/routes/static.js +2 -1
- package/dist/automations/steps/createRow.js +2 -4
- package/dist/automations/steps/deleteRow.js +1 -4
- package/dist/constants/index.js +12 -5
- package/dist/db/linkedRows/index.js +4 -5
- package/dist/definitions/datasource.js +1 -0
- package/dist/environment.js +1 -0
- package/dist/integrations/base/sql.js +13 -6
- package/dist/integrations/googlesheets.js +340 -0
- package/dist/integrations/index.js +3 -0
- package/dist/integrations/utils.js +57 -8
- package/dist/middleware/authorized.js +55 -30
- 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 +8 -5
- package/dist/tests/utilities/TestConfiguration.js +10 -6
- package/dist/threads/query.js +4 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utilities/rowProcessor/index.js +18 -11
- package/dist/utilities/rowProcessor/utils.js +14 -4
- 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/dist/utilities/workerRequests.js +0 -20
- package/nodemon.json +1 -1
- package/package.json +9 -6
- package/src/api/controllers/application.js +52 -24
- package/src/api/controllers/auth.js +4 -0
- package/src/api/controllers/datasource.js +12 -0
- package/src/api/controllers/row/ExternalRequest.ts +1 -1
- package/src/api/controllers/row/internal.js +29 -50
- package/src/api/controllers/row/internalSearch.js +12 -4
- package/src/api/controllers/row/staticFormula.js +157 -0
- package/src/api/controllers/row/utils.js +6 -12
- package/src/api/controllers/static/index.js +63 -10
- package/src/api/controllers/table/bulkFormula.js +183 -0
- package/src/api/controllers/table/index.js +16 -24
- package/src/api/controllers/table/internal.js +9 -1
- package/src/api/controllers/table/utils.js +80 -11
- package/src/api/controllers/user.js +2 -0
- package/src/api/routes/index.js +0 -2
- package/src/api/routes/static.js +5 -0
- package/src/api/routes/tests/application.spec.js +2 -2
- package/src/api/routes/tests/auth.spec.js +1 -2
- package/src/api/routes/tests/static.spec.js +98 -0
- package/src/automations/steps/createRow.js +2 -4
- package/src/automations/steps/deleteRow.js +1 -4
- package/src/constants/index.js +17 -5
- package/src/db/linkedRows/index.js +4 -5
- package/src/definitions/common.ts +3 -0
- package/src/definitions/datasource.ts +3 -0
- package/src/environment.js +1 -0
- package/src/integrations/base/sql.ts +14 -7
- package/src/integrations/googlesheets.ts +353 -0
- package/src/integrations/index.ts +3 -0
- package/src/integrations/tests/sql.spec.js +16 -0
- package/src/integrations/utils.ts +71 -10
- package/src/middleware/authorized.js +64 -30
- package/src/middleware/tests/authorized.spec.js +6 -4
- 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/tests/utilities/TestConfiguration.js +10 -6
- package/src/threads/query.js +5 -0
- package/src/utilities/rowProcessor/index.js +24 -12
- package/src/utilities/rowProcessor/utils.js +23 -7
- 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/workerRequests.js +0 -23
- package/builder/assets/index.39e01193.css +0 -1
- package/dist/api/controllers/hosting.js +0 -30
- package/dist/api/routes/hosting.js +0 -11
- package/src/api/controllers/hosting.js +0 -22
- package/src/api/routes/hosting.js +0 -13
- package/src/api/routes/tests/hosting.spec.js +0 -36
- package/src/utilities/usageQuota.js +0 -73
|
@@ -20,7 +20,7 @@ const { cloneDeep } = require("lodash/fp");
|
|
|
20
20
|
const { processObject } = require("@budibase/string-templates");
|
|
21
21
|
const { getAllApps, isDevAppID, getDeployedAppID, Replication, } = require("@budibase/backend-core/db");
|
|
22
22
|
const { USERS_TABLE_SCHEMA } = require("../../constants");
|
|
23
|
-
const {
|
|
23
|
+
const { removeAppFromUserRoles } = require("../../utilities/workerRequests");
|
|
24
24
|
const { clientLibraryPath, stringToReadStream } = require("../../utilities");
|
|
25
25
|
const { getAllLocks } = require("../../utilities/redis");
|
|
26
26
|
const { updateClientLibrary, backupClientLibrary, revertClientLibrary, } = require("../../utilities/fileSystem/clientLibrary");
|
|
@@ -49,31 +49,44 @@ function getUserRoleId(ctx) {
|
|
|
49
49
|
? BUILTIN_ROLE_IDS.PUBLIC
|
|
50
50
|
: ctx.user.role._id;
|
|
51
51
|
}
|
|
52
|
-
function
|
|
52
|
+
function getAppUrl(ctx) {
|
|
53
53
|
return __awaiter(this, void 0, void 0, function* () {
|
|
54
|
+
// construct the url
|
|
54
55
|
let url;
|
|
55
56
|
if (ctx.request.body.url) {
|
|
57
|
+
// if the url is provided, use that
|
|
56
58
|
url = encodeURI(ctx.request.body.url);
|
|
57
59
|
}
|
|
58
60
|
else if (ctx.request.body.name) {
|
|
61
|
+
// otherwise use the name
|
|
59
62
|
url = encodeURI(`${ctx.request.body.name}`);
|
|
60
63
|
}
|
|
61
64
|
if (url) {
|
|
62
65
|
url = `/${url.replace(URL_REGEX_SLASH, "")}`.toLowerCase();
|
|
63
66
|
}
|
|
64
|
-
if (!env.SELF_HOSTED) {
|
|
65
|
-
return url;
|
|
66
|
-
}
|
|
67
|
-
const deployedApps = yield getDeployedApps();
|
|
68
|
-
if (url &&
|
|
69
|
-
deployedApps[url] != null &&
|
|
70
|
-
ctx.params != null &&
|
|
71
|
-
deployedApps[url].appId !== ctx.params.appId) {
|
|
72
|
-
ctx.throw(400, "App name/URL is already in use.");
|
|
73
|
-
}
|
|
74
67
|
return url;
|
|
75
68
|
});
|
|
76
69
|
}
|
|
70
|
+
const checkAppUrl = (ctx, apps, url, currentAppId) => {
|
|
71
|
+
if (currentAppId) {
|
|
72
|
+
apps = apps.filter(app => app.appId !== currentAppId);
|
|
73
|
+
}
|
|
74
|
+
if (apps.some(app => app.url === url)) {
|
|
75
|
+
ctx.throw(400, "App URL is already in use.");
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
const checkAppName = (ctx, apps, name, currentAppId) => {
|
|
79
|
+
// TODO: Replace with Joi
|
|
80
|
+
if (!name) {
|
|
81
|
+
ctx.throw(400, "Name is required");
|
|
82
|
+
}
|
|
83
|
+
if (currentAppId) {
|
|
84
|
+
apps = apps.filter(app => app.appId !== currentAppId);
|
|
85
|
+
}
|
|
86
|
+
if (apps.some(app => app.name === name)) {
|
|
87
|
+
ctx.throw(400, "App name is already in use.");
|
|
88
|
+
}
|
|
89
|
+
};
|
|
77
90
|
function createInstance(template) {
|
|
78
91
|
return __awaiter(this, void 0, void 0, function* () {
|
|
79
92
|
const tenantId = isMultiTenant() ? getTenantId() : null;
|
|
@@ -167,6 +180,11 @@ exports.fetchAppPackage = (ctx) => __awaiter(void 0, void 0, void 0, function* (
|
|
|
167
180
|
};
|
|
168
181
|
});
|
|
169
182
|
exports.create = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
183
|
+
const apps = yield getAllApps(CouchDB, { dev: true });
|
|
184
|
+
const name = ctx.request.body.name;
|
|
185
|
+
checkAppName(ctx, apps, name);
|
|
186
|
+
const url = yield getAppUrl(ctx);
|
|
187
|
+
checkAppUrl(ctx, apps, url);
|
|
170
188
|
const { useTemplate, templateKey, templateString } = ctx.request.body;
|
|
171
189
|
const instanceConfig = {
|
|
172
190
|
useTemplate,
|
|
@@ -178,7 +196,6 @@ exports.create = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
178
196
|
}
|
|
179
197
|
const instance = yield createInstance(instanceConfig);
|
|
180
198
|
const appId = instance._id;
|
|
181
|
-
const url = yield getAppUrlIfNotInUse(ctx);
|
|
182
199
|
const db = new CouchDB(appId);
|
|
183
200
|
let _rev;
|
|
184
201
|
try {
|
|
@@ -196,7 +213,7 @@ exports.create = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
196
213
|
type: "app",
|
|
197
214
|
version: packageJson.version,
|
|
198
215
|
componentLibraries: ["@budibase/standard-components"],
|
|
199
|
-
name:
|
|
216
|
+
name: name,
|
|
200
217
|
url: url,
|
|
201
218
|
template: ctx.request.body.template,
|
|
202
219
|
instance: instance,
|
|
@@ -219,8 +236,21 @@ exports.create = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
219
236
|
ctx.status = 200;
|
|
220
237
|
ctx.body = newApplication;
|
|
221
238
|
});
|
|
239
|
+
// This endpoint currently operates as a PATCH rather than a PUT
|
|
240
|
+
// Thus name and url fields are handled only if present
|
|
222
241
|
exports.update = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
223
|
-
const
|
|
242
|
+
const apps = yield getAllApps(CouchDB, { dev: true });
|
|
243
|
+
// validation
|
|
244
|
+
const name = ctx.request.body.name;
|
|
245
|
+
if (name) {
|
|
246
|
+
checkAppName(ctx, apps, name, ctx.params.appId);
|
|
247
|
+
}
|
|
248
|
+
const url = yield getAppUrl(ctx);
|
|
249
|
+
if (url) {
|
|
250
|
+
checkAppUrl(ctx, apps, url, ctx.params.appId);
|
|
251
|
+
ctx.request.body.url = url;
|
|
252
|
+
}
|
|
253
|
+
const data = yield updateAppPackage(ctx.request.body, ctx.params.appId);
|
|
224
254
|
ctx.status = 200;
|
|
225
255
|
ctx.body = data;
|
|
226
256
|
});
|
|
@@ -239,7 +269,7 @@ exports.updateClient = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
239
269
|
version: packageJson.version,
|
|
240
270
|
revertableVersion: currentVersion,
|
|
241
271
|
};
|
|
242
|
-
const data = yield updateAppPackage(
|
|
272
|
+
const data = yield updateAppPackage(appPackageUpdates, ctx.params.appId);
|
|
243
273
|
ctx.status = 200;
|
|
244
274
|
ctx.body = data;
|
|
245
275
|
});
|
|
@@ -259,7 +289,7 @@ exports.revertClient = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
259
289
|
version: application.revertableVersion,
|
|
260
290
|
revertableVersion: null,
|
|
261
291
|
};
|
|
262
|
-
const data = yield updateAppPackage(
|
|
292
|
+
const data = yield updateAppPackage(appPackageUpdates, ctx.params.appId);
|
|
263
293
|
ctx.status = 200;
|
|
264
294
|
ctx.body = data;
|
|
265
295
|
});
|
|
@@ -326,11 +356,10 @@ exports.sync = (ctx, next) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
326
356
|
};
|
|
327
357
|
}
|
|
328
358
|
});
|
|
329
|
-
const updateAppPackage = (
|
|
330
|
-
const url = yield getAppUrlIfNotInUse(ctx);
|
|
359
|
+
const updateAppPackage = (appPackage, appId) => __awaiter(void 0, void 0, void 0, function* () {
|
|
331
360
|
const db = new CouchDB(appId);
|
|
332
361
|
const application = yield db.get(DocumentTypes.APP_METADATA);
|
|
333
|
-
const newAppPackage = Object.assign(Object.assign(
|
|
362
|
+
const newAppPackage = Object.assign(Object.assign({}, application), appPackage);
|
|
334
363
|
if (appPackage._rev !== application._rev) {
|
|
335
364
|
newAppPackage._rev = application._rev;
|
|
336
365
|
}
|
|
@@ -24,6 +24,8 @@ exports.fetchSelf = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
24
24
|
const user = yield getFullUser(ctx, userId);
|
|
25
25
|
// this shouldn't be returned by the app self
|
|
26
26
|
delete user.roles;
|
|
27
|
+
// forward the csrf token from the session
|
|
28
|
+
user.csrfToken = ctx.user.csrfToken;
|
|
27
29
|
if (appId) {
|
|
28
30
|
const db = new CouchDB(appId);
|
|
29
31
|
// remove the full roles structure
|
|
@@ -31,6 +33,8 @@ exports.fetchSelf = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
31
33
|
try {
|
|
32
34
|
const userTable = yield db.get(InternalTables.USER_METADATA);
|
|
33
35
|
const metadata = yield db.get(userId);
|
|
36
|
+
// make sure there is never a stale csrf token
|
|
37
|
+
delete metadata.csrfToken;
|
|
34
38
|
// specifically needs to make sure is enriched
|
|
35
39
|
ctx.body = yield outputProcessing(ctx, userTable, Object.assign(Object.assign({}, user), metadata));
|
|
36
40
|
}
|
|
@@ -28,6 +28,12 @@ exports.fetch = function (ctx) {
|
|
|
28
28
|
const datasources = (yield database.allDocs(getDatasourceParams(null, {
|
|
29
29
|
include_docs: true,
|
|
30
30
|
}))).rows.map(row => row.doc);
|
|
31
|
+
for (let datasource of datasources) {
|
|
32
|
+
if (datasource.config && datasource.config.auth) {
|
|
33
|
+
// strip secrets from response so they don't show in the network request
|
|
34
|
+
delete datasource.config.auth;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
31
37
|
ctx.body = [bbInternalDb, ...datasources];
|
|
32
38
|
});
|
|
33
39
|
};
|
|
@@ -78,8 +84,13 @@ exports.update = function (ctx) {
|
|
|
78
84
|
const db = new CouchDB(ctx.appId);
|
|
79
85
|
const datasourceId = ctx.params.datasourceId;
|
|
80
86
|
let datasource = yield db.get(datasourceId);
|
|
87
|
+
const auth = datasource.config.auth;
|
|
81
88
|
yield invalidateVariables(datasource, ctx.request.body);
|
|
82
89
|
datasource = Object.assign(Object.assign({}, datasource), ctx.request.body);
|
|
90
|
+
if (auth && !ctx.request.body.auth) {
|
|
91
|
+
// don't strip auth config from DB
|
|
92
|
+
datasource.config.auth = auth;
|
|
93
|
+
}
|
|
83
94
|
const response = yield db.put(datasource);
|
|
84
95
|
datasource._rev = response.rev;
|
|
85
96
|
// Drain connection pools when configuration is changed
|
|
@@ -431,6 +431,7 @@ var External;
|
|
|
431
431
|
* all and then re-create, as theres no chance of losing data (e.g. delete succeed, but write fail).
|
|
432
432
|
*/
|
|
433
433
|
handleManyRelationships(mainTableId, row, relationships) {
|
|
434
|
+
var _a;
|
|
434
435
|
return __awaiter(this, void 0, void 0, function* () {
|
|
435
436
|
const { appId } = this;
|
|
436
437
|
// if we're creating (in a through table) need to wipe the existing ones first
|
|
@@ -442,7 +443,7 @@ var External;
|
|
|
442
443
|
const linkTable = this.getTable(tableId);
|
|
443
444
|
// @ts-ignore
|
|
444
445
|
const linkPrimary = linkTable.primary[0];
|
|
445
|
-
const rows = related[key].rows || [];
|
|
446
|
+
const rows = ((_a = related[key]) === null || _a === void 0 ? void 0 : _a.rows) || [];
|
|
446
447
|
const found = rows.find((row) => row[linkPrimary] === relationship.id ||
|
|
447
448
|
row[linkPrimary] === body[linkPrimary]);
|
|
448
449
|
const operation = isUpdate
|
|
@@ -21,11 +21,10 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
21
21
|
};
|
|
22
22
|
const CouchDB = require("../../../db");
|
|
23
23
|
const linkRows = require("../../../db/linkedRows");
|
|
24
|
-
const {
|
|
24
|
+
const { generateRowID, getRowParams, DocumentTypes, InternalTables, } = require("../../../db/utils");
|
|
25
25
|
const userController = require("../user");
|
|
26
|
-
const { inputProcessing, outputProcessing,
|
|
26
|
+
const { inputProcessing, outputProcessing, cleanupAttachments, } = require("../../../utilities/rowProcessor");
|
|
27
27
|
const { FieldTypes } = require("../../../constants");
|
|
28
|
-
const { isEqual } = require("lodash");
|
|
29
28
|
const { validate, findRow } = require("./utils");
|
|
30
29
|
const { fullSearch, paginatedSearch } = require("./internalSearch");
|
|
31
30
|
const { getGlobalUsersFromMetadata } = require("../../../utilities/global");
|
|
@@ -33,59 +32,12 @@ const inMemoryViews = require("../../../db/inMemoryView");
|
|
|
33
32
|
const env = require("../../../environment");
|
|
34
33
|
const { migrateToInMemoryView, migrateToDesignView, getFromDesignDoc, getFromMemoryDoc, } = require("../view/utils");
|
|
35
34
|
const { cloneDeep } = require("lodash/fp");
|
|
35
|
+
const { finaliseRow, updateRelatedFormula } = require("./staticFormula");
|
|
36
36
|
const CALCULATION_TYPES = {
|
|
37
37
|
SUM: "sum",
|
|
38
38
|
COUNT: "count",
|
|
39
39
|
STATS: "stats",
|
|
40
40
|
};
|
|
41
|
-
function storeResponse(ctx, db, row, oldTable, table) {
|
|
42
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
43
|
-
row.type = "row";
|
|
44
|
-
// don't worry about rev, tables handle rev/lastID updates
|
|
45
|
-
// if another row has been written since processing this will
|
|
46
|
-
// handle the auto ID clash
|
|
47
|
-
if (!isEqual(oldTable, table)) {
|
|
48
|
-
try {
|
|
49
|
-
yield db.put(table);
|
|
50
|
-
}
|
|
51
|
-
catch (err) {
|
|
52
|
-
if (err.status === 409) {
|
|
53
|
-
const updatedTable = yield db.get(table._id);
|
|
54
|
-
let response = processAutoColumn(null, updatedTable, row, {
|
|
55
|
-
reprocessing: true,
|
|
56
|
-
});
|
|
57
|
-
yield db.put(response.table);
|
|
58
|
-
row = response.row;
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
throw err;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
const response = yield db.put(row);
|
|
66
|
-
row._rev = response.rev;
|
|
67
|
-
// process the row before return, to include relationships
|
|
68
|
-
row = yield outputProcessing(ctx, table, row, { squash: false });
|
|
69
|
-
return { row, table };
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
// doesn't do the outputProcessing
|
|
73
|
-
function getRawTableData(ctx, db, tableId) {
|
|
74
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
75
|
-
let rows;
|
|
76
|
-
if (tableId === InternalTables.USER_METADATA) {
|
|
77
|
-
yield userController.fetchMetadata(ctx);
|
|
78
|
-
rows = ctx.body;
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
const response = yield db.allDocs(getRowParams(tableId, null, {
|
|
82
|
-
include_docs: true,
|
|
83
|
-
}));
|
|
84
|
-
rows = response.rows.map(row => row.doc);
|
|
85
|
-
}
|
|
86
|
-
return rows;
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
41
|
function getView(db, viewName) {
|
|
90
42
|
return __awaiter(this, void 0, void 0, function* () {
|
|
91
43
|
let mainGetter = env.SELF_HOSTED ? getFromDesignDoc : getFromMemoryDoc;
|
|
@@ -114,6 +66,22 @@ function getView(db, viewName) {
|
|
|
114
66
|
return viewInfo;
|
|
115
67
|
});
|
|
116
68
|
}
|
|
69
|
+
function getRawTableData(ctx, db, tableId) {
|
|
70
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
71
|
+
let rows;
|
|
72
|
+
if (tableId === InternalTables.USER_METADATA) {
|
|
73
|
+
yield userController.fetchMetadata(ctx);
|
|
74
|
+
rows = ctx.body;
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
const response = yield db.allDocs(getRowParams(tableId, null, {
|
|
78
|
+
include_docs: true,
|
|
79
|
+
}));
|
|
80
|
+
rows = response.rows.map(row => row.doc);
|
|
81
|
+
}
|
|
82
|
+
return rows;
|
|
83
|
+
});
|
|
84
|
+
}
|
|
117
85
|
exports.patch = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
118
86
|
const appId = ctx.appId;
|
|
119
87
|
const db = new CouchDB(appId);
|
|
@@ -169,7 +137,10 @@ exports.patch = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
169
137
|
yield userController.updateMetadata(ctx);
|
|
170
138
|
return { row: ctx.body, table };
|
|
171
139
|
}
|
|
172
|
-
return
|
|
140
|
+
return finaliseRow(ctx.appId, table, row, {
|
|
141
|
+
oldTable: dbTable,
|
|
142
|
+
updateFormula: true,
|
|
143
|
+
});
|
|
173
144
|
});
|
|
174
145
|
exports.save = function (ctx) {
|
|
175
146
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -198,7 +169,10 @@ exports.save = function (ctx) {
|
|
|
198
169
|
tableId: row.tableId,
|
|
199
170
|
table,
|
|
200
171
|
});
|
|
201
|
-
return
|
|
172
|
+
return finaliseRow(ctx.appId, table, row, {
|
|
173
|
+
oldTable: dbTable,
|
|
174
|
+
updateFormula: true,
|
|
175
|
+
});
|
|
202
176
|
});
|
|
203
177
|
};
|
|
204
178
|
exports.fetchView = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -290,6 +264,8 @@ exports.destroy = function (ctx) {
|
|
|
290
264
|
});
|
|
291
265
|
// remove any attachments that were on the row from object storage
|
|
292
266
|
yield cleanupAttachments(appId, table, { row });
|
|
267
|
+
// remove any static formula
|
|
268
|
+
yield updateRelatedFormula(appId, table, row);
|
|
293
269
|
let response;
|
|
294
270
|
if (ctx.params.tableId === InternalTables.USER_METADATA) {
|
|
295
271
|
ctx.params = {
|
|
@@ -333,6 +309,7 @@ exports.bulkDestroy = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
333
309
|
}
|
|
334
310
|
// remove any attachments that were on the rows from object storage
|
|
335
311
|
yield cleanupAttachments(appId, table, { rows });
|
|
312
|
+
yield updateRelatedFormula(appId, table, rows);
|
|
336
313
|
yield Promise.all(updates);
|
|
337
314
|
return { response: { ok: true }, rows };
|
|
338
315
|
});
|
|
@@ -34,19 +34,27 @@ class QueryBuilder {
|
|
|
34
34
|
return this;
|
|
35
35
|
}
|
|
36
36
|
setLimit(limit) {
|
|
37
|
-
|
|
37
|
+
if (limit != null) {
|
|
38
|
+
this.limit = limit;
|
|
39
|
+
}
|
|
38
40
|
return this;
|
|
39
41
|
}
|
|
40
42
|
setSort(sort) {
|
|
41
|
-
|
|
43
|
+
if (sort != null) {
|
|
44
|
+
this.sort = sort;
|
|
45
|
+
}
|
|
42
46
|
return this;
|
|
43
47
|
}
|
|
44
48
|
setSortOrder(sortOrder) {
|
|
45
|
-
|
|
49
|
+
if (sortOrder != null) {
|
|
50
|
+
this.sortOrder = sortOrder;
|
|
51
|
+
}
|
|
46
52
|
return this;
|
|
47
53
|
}
|
|
48
54
|
setSortType(sortType) {
|
|
49
|
-
|
|
55
|
+
if (sortType != null) {
|
|
56
|
+
this.sortType = sortType;
|
|
57
|
+
}
|
|
50
58
|
return this;
|
|
51
59
|
}
|
|
52
60
|
setBookmark(bookmark) {
|
|
@@ -0,0 +1,147 @@
|
|
|
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 CouchDB = require("../../../db");
|
|
12
|
+
const { getRowParams } = require("../../../db/utils");
|
|
13
|
+
const { outputProcessing, processAutoColumn, processFormulas, } = require("../../../utilities/rowProcessor");
|
|
14
|
+
const { FieldTypes, FormulaTypes } = require("../../../constants");
|
|
15
|
+
const { isEqual } = require("lodash");
|
|
16
|
+
const { cloneDeep } = require("lodash/fp");
|
|
17
|
+
/**
|
|
18
|
+
* This function runs through a list of enriched rows, looks at the rows which
|
|
19
|
+
* are related and then checks if they need the state of their formulas
|
|
20
|
+
* updated.
|
|
21
|
+
* NOTE: this will only for affect static formulas.
|
|
22
|
+
*/
|
|
23
|
+
exports.updateRelatedFormula = (appId, table, enrichedRows) => __awaiter(void 0, void 0, void 0, function* () {
|
|
24
|
+
const db = new CouchDB(appId);
|
|
25
|
+
// no formula to update, we're done
|
|
26
|
+
if (!table.relatedFormula) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
let promises = [];
|
|
30
|
+
for (let enrichedRow of Array.isArray(enrichedRows)
|
|
31
|
+
? enrichedRows
|
|
32
|
+
: [enrichedRows]) {
|
|
33
|
+
// the related rows by tableId
|
|
34
|
+
let relatedRows = {};
|
|
35
|
+
for (let [key, field] of Object.entries(enrichedRow)) {
|
|
36
|
+
const columnDefinition = table.schema[key];
|
|
37
|
+
if (columnDefinition && columnDefinition.type === FieldTypes.LINK) {
|
|
38
|
+
const relatedTableId = columnDefinition.tableId;
|
|
39
|
+
if (!relatedRows[relatedTableId]) {
|
|
40
|
+
relatedRows[relatedTableId] = [];
|
|
41
|
+
}
|
|
42
|
+
relatedRows[relatedTableId] = relatedRows[relatedTableId].concat(field);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
for (let tableId of table.relatedFormula) {
|
|
46
|
+
let relatedTable;
|
|
47
|
+
try {
|
|
48
|
+
// no rows to update, skip
|
|
49
|
+
if (!relatedRows[tableId] || relatedRows[tableId].length === 0) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
relatedTable = yield db.get(tableId);
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
// no error scenario, table doesn't seem to exist anymore, ignore
|
|
56
|
+
}
|
|
57
|
+
for (let column of Object.values(relatedTable.schema)) {
|
|
58
|
+
// needs updated in related rows
|
|
59
|
+
if (column.type === FieldTypes.FORMULA &&
|
|
60
|
+
column.formulaType === FormulaTypes.STATIC) {
|
|
61
|
+
// re-enrich rows for all the related, don't update the related formula for them
|
|
62
|
+
promises = promises.concat(relatedRows[tableId].map(related => exports.finaliseRow(appId, relatedTable, related, {
|
|
63
|
+
updateFormula: false,
|
|
64
|
+
})));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
yield Promise.all(promises);
|
|
70
|
+
});
|
|
71
|
+
exports.updateAllFormulasInTable = (appId, table) => __awaiter(void 0, void 0, void 0, function* () {
|
|
72
|
+
const db = new CouchDB(appId);
|
|
73
|
+
// start by getting the raw rows (which will be written back to DB after update)
|
|
74
|
+
let rows = (yield db.allDocs(getRowParams(table._id, null, {
|
|
75
|
+
include_docs: true,
|
|
76
|
+
}))).rows.map(row => row.doc);
|
|
77
|
+
// now enrich the rows, note the clone so that we have the base state of the
|
|
78
|
+
// rows so that we don't write any of the enriched information back
|
|
79
|
+
let enrichedRows = yield outputProcessing({ appId }, table, cloneDeep(rows), {
|
|
80
|
+
squash: false,
|
|
81
|
+
});
|
|
82
|
+
const updatedRows = [];
|
|
83
|
+
for (let row of rows) {
|
|
84
|
+
// find the enriched row, if found process the formulas
|
|
85
|
+
const enrichedRow = enrichedRows.find(enriched => enriched._id === row._id);
|
|
86
|
+
if (enrichedRow) {
|
|
87
|
+
const processed = processFormulas(table, cloneDeep(row), {
|
|
88
|
+
dynamic: false,
|
|
89
|
+
contextRows: enrichedRow,
|
|
90
|
+
});
|
|
91
|
+
// values have changed, need to add to bulk docs to update
|
|
92
|
+
if (!isEqual(processed, row)) {
|
|
93
|
+
updatedRows.push(processed);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
yield db.bulkDocs(updatedRows);
|
|
98
|
+
});
|
|
99
|
+
/**
|
|
100
|
+
* This function runs at the end of the save/patch functions of the row controller, all this
|
|
101
|
+
* really does is enrich the row, handle any static formula processing, then return the enriched
|
|
102
|
+
* row. The reason we need to return the enriched row is that the automation row created trigger
|
|
103
|
+
* expects the row to be totally enriched/contain all relationships.
|
|
104
|
+
*/
|
|
105
|
+
exports.finaliseRow = (appId, table, row, { oldTable, updateFormula } = { updateFormula: true }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
106
|
+
const db = new CouchDB(appId);
|
|
107
|
+
row.type = "row";
|
|
108
|
+
// process the row before return, to include relationships
|
|
109
|
+
let enrichedRow = yield outputProcessing({ appId }, table, cloneDeep(row), {
|
|
110
|
+
squash: false,
|
|
111
|
+
});
|
|
112
|
+
// use enriched row to generate formulas for saving, specifically only use as context
|
|
113
|
+
row = processFormulas(table, row, {
|
|
114
|
+
dynamic: false,
|
|
115
|
+
contextRows: enrichedRow,
|
|
116
|
+
});
|
|
117
|
+
// don't worry about rev, tables handle rev/lastID updates
|
|
118
|
+
// if another row has been written since processing this will
|
|
119
|
+
// handle the auto ID clash
|
|
120
|
+
if (oldTable && !isEqual(oldTable, table)) {
|
|
121
|
+
try {
|
|
122
|
+
yield db.put(table);
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
if (err.status === 409) {
|
|
126
|
+
const updatedTable = yield db.get(table._id);
|
|
127
|
+
let response = processAutoColumn(null, updatedTable, row, {
|
|
128
|
+
reprocessing: true,
|
|
129
|
+
});
|
|
130
|
+
yield db.put(response.table);
|
|
131
|
+
row = response.row;
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
throw err;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
const response = yield db.put(row);
|
|
139
|
+
// for response, calculate the formulas for the enriched row
|
|
140
|
+
enrichedRow._rev = response.rev;
|
|
141
|
+
enrichedRow = yield processFormulas(table, enrichedRow, { dynamic: false });
|
|
142
|
+
// this updates the related formulas in other rows based on the relations to this row
|
|
143
|
+
if (updateFormula) {
|
|
144
|
+
yield exports.updateRelatedFormula(appId, table, enrichedRow);
|
|
145
|
+
}
|
|
146
|
+
return { row: enrichedRow, table };
|
|
147
|
+
});
|
|
@@ -64,19 +64,17 @@ exports.validate = ({ appId, tableId, row, table }) => __awaiter(void 0, void 0,
|
|
|
64
64
|
}
|
|
65
65
|
let res;
|
|
66
66
|
// Validate.js doesn't seem to handle array
|
|
67
|
-
if (type === FieldTypes.ARRAY) {
|
|
68
|
-
|
|
69
|
-
// Check values are valid if values are specified
|
|
70
|
-
if (hasValues) {
|
|
67
|
+
if (type === FieldTypes.ARRAY && row[fieldName]) {
|
|
68
|
+
if (row[fieldName].length) {
|
|
71
69
|
row[fieldName].map(val => {
|
|
72
70
|
if (!constraints.inclusion.includes(val)) {
|
|
73
|
-
errors[fieldName] = "
|
|
71
|
+
errors[fieldName] = "Field not in list";
|
|
74
72
|
}
|
|
75
73
|
});
|
|
76
74
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
errors[fieldName] =
|
|
75
|
+
else if (constraints.presence && row[fieldName].length === 0) {
|
|
76
|
+
// non required MultiSelect creates an empty array, which should not throw errors
|
|
77
|
+
errors[fieldName] = [`${fieldName} is required`];
|
|
80
78
|
}
|
|
81
79
|
}
|
|
82
80
|
else if (type === FieldTypes.JSON && typeof row[fieldName] === "string") {
|
|
@@ -14,7 +14,7 @@ const { resolve, join } = require("../../../utilities/centralPath");
|
|
|
14
14
|
const uuid = require("uuid");
|
|
15
15
|
const { ObjectStoreBuckets } = require("../../../constants");
|
|
16
16
|
const { processString } = require("@budibase/string-templates");
|
|
17
|
-
const {
|
|
17
|
+
const { getAllApps } = require("@budibase/backend-core/db");
|
|
18
18
|
const CouchDB = require("../../../db");
|
|
19
19
|
const { loadHandlebarsFile, NODE_MODULES_PATH, TOP_LEVEL_PATH, } = require("../../../utilities/fileSystem");
|
|
20
20
|
const env = require("../../../environment");
|
|
@@ -22,6 +22,8 @@ const { clientLibraryPath } = require("../../../utilities");
|
|
|
22
22
|
const { upload } = require("../../../utilities/fileSystem");
|
|
23
23
|
const { attachmentsRelativeURL } = require("../../../utilities");
|
|
24
24
|
const { DocumentTypes } = require("../../../db/utils");
|
|
25
|
+
const AWS = require("aws-sdk");
|
|
26
|
+
const AWS_REGION = env.AWS_REGION ? env.AWS_REGION : "eu-west-1";
|
|
25
27
|
function prepareUpload({ s3Key, bucket, metadata, file }) {
|
|
26
28
|
return __awaiter(this, void 0, void 0, function* () {
|
|
27
29
|
const response = yield upload({
|
|
@@ -41,13 +43,15 @@ function prepareUpload({ s3Key, bucket, metadata, file }) {
|
|
|
41
43
|
};
|
|
42
44
|
});
|
|
43
45
|
}
|
|
44
|
-
function
|
|
46
|
+
function getAppIdFromUrl(ctx) {
|
|
45
47
|
return __awaiter(this, void 0, void 0, function* () {
|
|
46
|
-
// the "appId" component of the URL
|
|
48
|
+
// the "appId" component of the URL can be the id or the custom url
|
|
47
49
|
let possibleAppUrl = `/${encodeURI(ctx.params.appId).toLowerCase()}`;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
// search prod apps for a url that matches, exclude dev where id is always used
|
|
51
|
+
const apps = yield getAllApps(CouchDB, { dev: false });
|
|
52
|
+
const app = apps.filter(a => a.url && a.url.toLowerCase() === possibleAppUrl)[0];
|
|
53
|
+
if (app && app.appId) {
|
|
54
|
+
return app.appId;
|
|
51
55
|
}
|
|
52
56
|
else {
|
|
53
57
|
return ctx.params.appId;
|
|
@@ -80,10 +84,7 @@ exports.uploadFile = function (ctx) {
|
|
|
80
84
|
};
|
|
81
85
|
exports.serveApp = function (ctx) {
|
|
82
86
|
return __awaiter(this, void 0, void 0, function* () {
|
|
83
|
-
let appId = ctx
|
|
84
|
-
if (env.SELF_HOSTED) {
|
|
85
|
-
appId = yield checkForSelfHostedURL(ctx);
|
|
86
|
-
}
|
|
87
|
+
let appId = yield getAppIdFromUrl(ctx);
|
|
87
88
|
const App = require("./templates/BudibaseApp.svelte").default;
|
|
88
89
|
const db = new CouchDB(appId, { skip_setup: true });
|
|
89
90
|
const appInfo = yield db.get(DocumentTypes.APP_METADATA);
|
|
@@ -109,3 +110,51 @@ exports.serveClientLibrary = function (ctx) {
|
|
|
109
110
|
});
|
|
110
111
|
});
|
|
111
112
|
};
|
|
113
|
+
exports.getSignedUploadURL = function (ctx) {
|
|
114
|
+
var _a, _b, _c;
|
|
115
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
116
|
+
const database = new CouchDB(ctx.appId);
|
|
117
|
+
// Ensure datasource is valid
|
|
118
|
+
let datasource;
|
|
119
|
+
try {
|
|
120
|
+
const { datasourceId } = ctx.params;
|
|
121
|
+
datasource = yield database.get(datasourceId);
|
|
122
|
+
if (!datasource) {
|
|
123
|
+
ctx.throw(400, "The specified datasource could not be found");
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
ctx.throw(400, "The specified datasource could not be found");
|
|
128
|
+
}
|
|
129
|
+
// Ensure we aren't using a custom endpoint
|
|
130
|
+
if ((_a = datasource === null || datasource === void 0 ? void 0 : datasource.config) === null || _a === void 0 ? void 0 : _a.endpoint) {
|
|
131
|
+
ctx.throw(400, "S3 datasources with custom endpoints are not supported");
|
|
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: (_b = datasource === null || datasource === void 0 ? void 0 : datasource.config) === null || _b === void 0 ? void 0 : _b.accessKeyId,
|
|
146
|
+
secretAccessKey: (_c = datasource === null || datasource === void 0 ? void 0 : datasource.config) === null || _c === void 0 ? void 0 : _c.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
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
ctx.throw(400, error);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
ctx.body = { signedUrl, publicUrl };
|
|
159
|
+
});
|
|
160
|
+
};
|