@budibase/server 1.0.48 → 1.0.49-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.e083dcaf.js → index.21e57eb4.js} +234 -231
- package/builder/assets/index.83c0944f.css +1 -0
- package/builder/assets/{vendor.f9faf6ab.js → vendor.d526bfe8.js} +12 -12
- package/builder/index.html +3 -3
- package/coverage/clover.xml +2338 -2028
- package/coverage/coverage-final.json +100 -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 +53 -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/migrations.js.html +119 -0
- 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 +46 -31
- 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 +217 -73
- 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 +8 -8
- 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 +18 -18
- package/coverage/lcov-report/api/routes/index.js.html +3 -3
- 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/{hosting.js.html → migrations.js.html} +17 -14
- 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 +5 -5
- package/coverage/lcov-report/constants/index.js.html +53 -26
- 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 +114 -99
- 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 +270 -42
- 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 +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/{api/controllers/hosting.js.html → utilities/usageQuota/usageQuoteReset.js.html} +36 -48
- package/coverage/lcov-report/utilities/users.js.html +5 -5
- package/coverage/lcov-report/utilities/workerRequests.js.html +39 -108
- package/coverage/lcov.info +3656 -3057
- package/dist/api/controllers/application.js +61 -34
- package/dist/api/controllers/auth.js +4 -0
- package/dist/api/controllers/datasource.js +11 -0
- package/dist/api/controllers/migrations.js +21 -0
- 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 +41 -12
- package/dist/api/controllers/user.js +2 -0
- package/dist/api/routes/index.js +2 -2
- package/dist/api/routes/migrations.js +9 -0
- package/dist/api/routes/static.js +2 -1
- package/dist/app.js +35 -5
- package/dist/automations/steps/createRow.js +2 -4
- package/dist/automations/steps/deleteRow.js +1 -4
- package/dist/constants/index.js +7 -0
- package/dist/db/linkedRows/index.js +4 -5
- package/dist/definitions/datasource.js +1 -0
- package/dist/environment.js +2 -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 -9
- package/dist/middleware/authorized.js +55 -30
- package/dist/middleware/usageQuota.js +80 -13
- package/dist/migrations/functions/appUrls.js +46 -0
- package/dist/migrations/functions/quotas1.js +50 -0
- package/dist/migrations/functions/usageQuotas/index.js +20 -0
- package/dist/migrations/functions/usageQuotas/syncApps.js +32 -0
- package/dist/migrations/functions/usageQuotas/syncRows.js +35 -0
- package/dist/migrations/functions/userEmailViewCasing.js +24 -0
- package/dist/migrations/index.js +62 -0
- package/dist/package.json +8 -5
- package/dist/tests/utilities/TestConfiguration.js +13 -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/migrations.js +13 -0
- 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 +57 -9
- package/src/api/controllers/user.js +2 -0
- package/src/api/routes/index.js +2 -2
- package/src/api/routes/migrations.js +14 -0
- 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/app.ts +18 -5
- package/src/automations/steps/createRow.js +2 -4
- package/src/automations/steps/deleteRow.js +1 -4
- package/src/constants/index.js +9 -0
- 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 +2 -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 -11
- 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 +91 -15
- package/src/migrations/functions/appUrls.ts +34 -0
- package/src/migrations/functions/quotas1.ts +20 -0
- package/src/migrations/functions/tests/appUrls.spec.js +29 -0
- package/src/migrations/functions/tests/quotas1.spec.js +27 -0
- package/src/migrations/functions/tests/userEmailViewCasing.spec.js +25 -0
- package/src/migrations/functions/usageQuotas/index.ts +8 -0
- package/src/migrations/functions/usageQuotas/syncApps.ts +18 -0
- package/src/migrations/functions/usageQuotas/syncRows.ts +21 -0
- package/src/migrations/functions/usageQuotas/tests/syncApps.spec.js +37 -0
- package/src/migrations/functions/usageQuotas/tests/syncRows.spec.js +43 -0
- package/src/migrations/functions/userEmailViewCasing.ts +13 -0
- package/src/migrations/index.ts +56 -0
- package/src/tests/utilities/TestConfiguration.js +14 -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
|
@@ -180,6 +180,8 @@ function processAutoColumn(
|
|
|
180
180
|
}
|
|
181
181
|
exports.processAutoColumn = processAutoColumn
|
|
182
182
|
|
|
183
|
+
exports.processFormulas = processFormulas
|
|
184
|
+
|
|
183
185
|
/**
|
|
184
186
|
* This will coerce a value to the correct types based on the type transform map
|
|
185
187
|
* @param {object} row The value to coerce
|
|
@@ -229,11 +231,12 @@ exports.inputProcessing = (
|
|
|
229
231
|
}
|
|
230
232
|
continue
|
|
231
233
|
}
|
|
232
|
-
//
|
|
233
|
-
// type coercion cannot completely remove the field, so have to do it here
|
|
234
|
+
// remove any formula values, they are to be generated
|
|
234
235
|
if (field.type === FieldTypes.FORMULA) {
|
|
235
236
|
delete clonedRow[key]
|
|
236
|
-
}
|
|
237
|
+
}
|
|
238
|
+
// otherwise coerce what is there to correct types
|
|
239
|
+
else {
|
|
237
240
|
clonedRow[key] = exports.coerce(value, field.type)
|
|
238
241
|
}
|
|
239
242
|
}
|
|
@@ -250,7 +253,7 @@ exports.inputProcessing = (
|
|
|
250
253
|
/**
|
|
251
254
|
* This function enriches the input rows with anything they are supposed to contain, for example
|
|
252
255
|
* link records or attachment links.
|
|
253
|
-
* @param {
|
|
256
|
+
* @param {string} appId the app in which the request is looking for enriched rows.
|
|
254
257
|
* @param {object} table the table from which these rows came from originally, this is used to determine
|
|
255
258
|
* the schema of the rows and then enrich.
|
|
256
259
|
* @param {object[]|object} rows the rows which are to be enriched.
|
|
@@ -258,22 +261,21 @@ exports.inputProcessing = (
|
|
|
258
261
|
* @returns {object[]|object} the enriched rows will be returned.
|
|
259
262
|
*/
|
|
260
263
|
exports.outputProcessing = async (
|
|
261
|
-
|
|
264
|
+
{ appId },
|
|
262
265
|
table,
|
|
263
266
|
rows,
|
|
264
267
|
opts = { squash: true }
|
|
265
268
|
) => {
|
|
266
|
-
const appId = ctx.appId
|
|
267
269
|
let wasArray = true
|
|
268
270
|
if (!(rows instanceof Array)) {
|
|
269
271
|
rows = [rows]
|
|
270
272
|
wasArray = false
|
|
271
273
|
}
|
|
272
274
|
// attach any linked row information
|
|
273
|
-
let enriched = await linkRows.attachFullLinkedDocs(
|
|
275
|
+
let enriched = await linkRows.attachFullLinkedDocs(appId, table, rows)
|
|
274
276
|
|
|
275
277
|
// process formulas
|
|
276
|
-
enriched = processFormulas(table, enriched)
|
|
278
|
+
enriched = processFormulas(table, enriched, { dynamic: true })
|
|
277
279
|
|
|
278
280
|
// update the attachments URL depending on hosting
|
|
279
281
|
for (let [property, column] of Object.entries(table.schema)) {
|
|
@@ -305,9 +307,15 @@ exports.outputProcessing = async (
|
|
|
305
307
|
* @param {any} row optional - the row being removed.
|
|
306
308
|
* @param {any} rows optional - if multiple rows being deleted can do this in bulk.
|
|
307
309
|
* @param {any} oldRow optional - if updating a row this will determine the difference.
|
|
310
|
+
* @param {any} oldTable optional - if updating a table, can supply the old table to look for
|
|
311
|
+
* deleted attachment columns.
|
|
308
312
|
* @return {Promise<void>} When all attachments have been removed this will return.
|
|
309
313
|
*/
|
|
310
|
-
exports.cleanupAttachments = async (
|
|
314
|
+
exports.cleanupAttachments = async (
|
|
315
|
+
appId,
|
|
316
|
+
table,
|
|
317
|
+
{ row, rows, oldRow, oldTable }
|
|
318
|
+
) => {
|
|
311
319
|
if (!isProdAppID(appId)) {
|
|
312
320
|
const prodAppId = getDeployedAppID(appId)
|
|
313
321
|
// if prod exists, then don't allow deleting
|
|
@@ -322,12 +330,16 @@ exports.cleanupAttachments = async (appId, table, { row, rows, oldRow }) => {
|
|
|
322
330
|
files = files.concat(row[key].map(attachment => attachment.key))
|
|
323
331
|
}
|
|
324
332
|
}
|
|
325
|
-
|
|
333
|
+
const schemaToUse = oldTable ? oldTable.schema : table.schema
|
|
334
|
+
for (let [key, schema] of Object.entries(schemaToUse)) {
|
|
326
335
|
if (schema.type !== FieldTypes.ATTACHMENT) {
|
|
327
336
|
continue
|
|
328
337
|
}
|
|
329
|
-
//
|
|
330
|
-
if (
|
|
338
|
+
// old table had this column, new table doesn't - delete it
|
|
339
|
+
if (oldTable && !table.schema[key]) {
|
|
340
|
+
rows.forEach(row => addFiles(row, key))
|
|
341
|
+
} else if (oldRow && row) {
|
|
342
|
+
// if updating, need to manage the differences
|
|
331
343
|
files = files.concat(getRemovedAttachmentKeys(oldRow, row, key))
|
|
332
344
|
} else if (row) {
|
|
333
345
|
addFiles(row, key)
|
|
@@ -1,23 +1,39 @@
|
|
|
1
|
-
const { FieldTypes } = require("../../constants")
|
|
1
|
+
const { FieldTypes, FormulaTypes } = require("../../constants")
|
|
2
2
|
const { processStringSync } = require("@budibase/string-templates")
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Looks through the rows provided and finds formulas - which it then processes.
|
|
6
6
|
*/
|
|
7
|
-
exports.processFormulas = (
|
|
7
|
+
exports.processFormulas = (
|
|
8
|
+
table,
|
|
9
|
+
rows,
|
|
10
|
+
{ dynamic, contextRows } = { dynamic: true }
|
|
11
|
+
) => {
|
|
8
12
|
const single = !Array.isArray(rows)
|
|
9
13
|
if (single) {
|
|
10
14
|
rows = [rows]
|
|
15
|
+
contextRows = contextRows ? [contextRows] : contextRows
|
|
11
16
|
}
|
|
12
17
|
for (let [column, schema] of Object.entries(table.schema)) {
|
|
13
|
-
|
|
18
|
+
const isStatic = schema.formulaType === FormulaTypes.STATIC
|
|
19
|
+
if (
|
|
20
|
+
schema.type !== FieldTypes.FORMULA ||
|
|
21
|
+
(dynamic && isStatic) ||
|
|
22
|
+
(!dynamic && !isStatic)
|
|
23
|
+
) {
|
|
14
24
|
continue
|
|
15
25
|
}
|
|
16
26
|
// iterate through rows and process formula
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
27
|
+
for (let i = 0; i < rows.length; i++) {
|
|
28
|
+
if (schema.formula) {
|
|
29
|
+
let row = rows[i]
|
|
30
|
+
let context = contextRows ? contextRows[i] : row
|
|
31
|
+
rows[i] = {
|
|
32
|
+
...row,
|
|
33
|
+
[column]: processStringSync(schema.formula, context),
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
21
37
|
}
|
|
22
38
|
return single ? rows[0] : rows
|
|
23
39
|
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
const getTenantId = jest.fn()
|
|
2
|
+
jest.mock("@budibase/backend-core/tenancy", () => ({
|
|
3
|
+
getTenantId
|
|
4
|
+
}))
|
|
5
|
+
const usageQuota = require("../../usageQuota")
|
|
6
|
+
const env = require("../../../environment")
|
|
7
|
+
|
|
8
|
+
class TestConfiguration {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.enableQuotas()
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
enableQuotas = () => {
|
|
14
|
+
env.USE_QUOTAS = 1
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
disableQuotas = () => {
|
|
18
|
+
env.USE_QUOTAS = null
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
setTenantId = (tenantId) => {
|
|
22
|
+
getTenantId.mockReturnValue(tenantId)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
setExcludedTenants = (tenants) => {
|
|
26
|
+
env.EXCLUDE_QUOTAS_TENANTS = tenants
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
reset = () => {
|
|
30
|
+
this.disableQuotas()
|
|
31
|
+
this.setExcludedTenants(null)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
describe("usageQuota", () => {
|
|
36
|
+
let config
|
|
37
|
+
|
|
38
|
+
beforeEach(() => {
|
|
39
|
+
config = new TestConfiguration()
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
afterEach(() => {
|
|
43
|
+
config.reset()
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
describe("useQuotas", () => {
|
|
47
|
+
it("works when no settings have been provided", () => {
|
|
48
|
+
config.reset()
|
|
49
|
+
expect(usageQuota.useQuotas()).toBe(false)
|
|
50
|
+
})
|
|
51
|
+
it("honours USE_QUOTAS setting", () => {
|
|
52
|
+
config.disableQuotas()
|
|
53
|
+
expect(usageQuota.useQuotas()).toBe(false)
|
|
54
|
+
|
|
55
|
+
config.enableQuotas()
|
|
56
|
+
expect(usageQuota.useQuotas()).toBe(true)
|
|
57
|
+
})
|
|
58
|
+
it("honours EXCLUDE_QUOTAS_TENANTS setting", () => {
|
|
59
|
+
config.setTenantId("test")
|
|
60
|
+
|
|
61
|
+
// tenantId is in the list
|
|
62
|
+
config.setExcludedTenants("test, test2, test2")
|
|
63
|
+
expect(usageQuota.useQuotas()).toBe(false)
|
|
64
|
+
config.setExcludedTenants("test,test2,test2")
|
|
65
|
+
expect(usageQuota.useQuotas()).toBe(false)
|
|
66
|
+
|
|
67
|
+
// tenantId is not in the list
|
|
68
|
+
config.setTenantId("other")
|
|
69
|
+
expect(usageQuota.useQuotas()).toBe(true)
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
})
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
const env = require("../../environment")
|
|
2
|
+
const { getGlobalDB, getTenantId } = require("@budibase/backend-core/tenancy")
|
|
3
|
+
const {
|
|
4
|
+
StaticDatabases,
|
|
5
|
+
generateNewUsageQuotaDoc,
|
|
6
|
+
} = require("@budibase/backend-core/db")
|
|
7
|
+
|
|
8
|
+
exports.useQuotas = () => {
|
|
9
|
+
// check if quotas are enabled
|
|
10
|
+
if (env.USE_QUOTAS) {
|
|
11
|
+
// check if there are any tenants without limits
|
|
12
|
+
if (env.EXCLUDE_QUOTAS_TENANTS) {
|
|
13
|
+
const excludedTenants = env.EXCLUDE_QUOTAS_TENANTS.replace(
|
|
14
|
+
/\s/g,
|
|
15
|
+
""
|
|
16
|
+
).split(",")
|
|
17
|
+
const tenantId = getTenantId()
|
|
18
|
+
if (excludedTenants.includes(tenantId)) {
|
|
19
|
+
return false
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return true
|
|
23
|
+
}
|
|
24
|
+
return false
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
exports.Properties = {
|
|
28
|
+
ROW: "rows",
|
|
29
|
+
UPLOAD: "storage", // doesn't work yet
|
|
30
|
+
VIEW: "views", // doesn't work yet
|
|
31
|
+
USER: "users", // doesn't work yet
|
|
32
|
+
AUTOMATION: "automationRuns", // doesn't work yet
|
|
33
|
+
APPS: "apps",
|
|
34
|
+
EMAILS: "emails", // doesn't work yet
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
exports.getUsageQuotaDoc = async db => {
|
|
38
|
+
let quota
|
|
39
|
+
try {
|
|
40
|
+
quota = await db.get(StaticDatabases.GLOBAL.docs.usageQuota)
|
|
41
|
+
} catch (err) {
|
|
42
|
+
// doc doesn't exist. Create it
|
|
43
|
+
quota = generateNewUsageQuotaDoc()
|
|
44
|
+
const response = await db.put(quota)
|
|
45
|
+
quota._rev = response.rev
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return quota
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Given a specified tenantId this will add to the usage object for the specified property.
|
|
53
|
+
* @param {string} property The property which is to be added to (within the nested usageQuota object).
|
|
54
|
+
* @param {number} usage The amount (this can be negative) to adjust the number by.
|
|
55
|
+
* @returns {Promise<void>} When this completes the API key will now be up to date - the quota period may have
|
|
56
|
+
* also been reset after this call.
|
|
57
|
+
*/
|
|
58
|
+
exports.update = async (property, usage, opts = { dryRun: false }) => {
|
|
59
|
+
if (!exports.useQuotas()) {
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
const db = getGlobalDB()
|
|
65
|
+
const quota = await exports.getUsageQuotaDoc(db)
|
|
66
|
+
|
|
67
|
+
// increment the quota
|
|
68
|
+
quota.usageQuota[property] += usage
|
|
69
|
+
|
|
70
|
+
if (
|
|
71
|
+
quota.usageQuota[property] > quota.usageLimits[property] &&
|
|
72
|
+
usage > 0 // allow for decrementing usage when the quota is already exceeded
|
|
73
|
+
) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
`You have exceeded your usage quota of ${quota.usageLimits[property]} ${property}.`
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (quota.usageQuota[property] < 0) {
|
|
80
|
+
// never go negative if the quota has previously been exceeded
|
|
81
|
+
quota.usageQuota[property] = 0
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// update the usage quotas
|
|
85
|
+
if (!opts.dryRun) {
|
|
86
|
+
await db.put(quota)
|
|
87
|
+
}
|
|
88
|
+
} catch (err) {
|
|
89
|
+
console.error(`Error updating usage quotas for ${property}`, err)
|
|
90
|
+
throw err
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
const { getRowParams, USER_METDATA_PREFIX } = require("../../db/utils")
|
|
2
|
+
const CouchDB = require("../../db")
|
|
3
|
+
const { isDevAppID, getDevelopmentAppID } = require("@budibase/backend-core/db")
|
|
4
|
+
|
|
5
|
+
const ROW_EXCLUSIONS = [USER_METDATA_PREFIX]
|
|
6
|
+
|
|
7
|
+
const getAppPairs = appIds => {
|
|
8
|
+
// collect the app ids into dev / prod pairs
|
|
9
|
+
// keyed by the dev app id
|
|
10
|
+
const pairs = {}
|
|
11
|
+
for (let appId of appIds) {
|
|
12
|
+
const devId = getDevelopmentAppID(appId)
|
|
13
|
+
if (!pairs[devId]) {
|
|
14
|
+
pairs[devId] = {}
|
|
15
|
+
}
|
|
16
|
+
if (isDevAppID(appId)) {
|
|
17
|
+
pairs[devId].devId = appId
|
|
18
|
+
} else {
|
|
19
|
+
pairs[devId].prodId = appId
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return pairs
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const getAppRows = async appId => {
|
|
26
|
+
const appDb = new CouchDB(appId)
|
|
27
|
+
const response = await appDb.allDocs(
|
|
28
|
+
getRowParams(null, null, {
|
|
29
|
+
include_docs: false,
|
|
30
|
+
})
|
|
31
|
+
)
|
|
32
|
+
return response.rows
|
|
33
|
+
.map(r => r.id)
|
|
34
|
+
.filter(id => {
|
|
35
|
+
for (let exclusion of ROW_EXCLUSIONS) {
|
|
36
|
+
if (id.startsWith(exclusion)) {
|
|
37
|
+
return false
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return true
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Return a set of all rows in the given app ids.
|
|
46
|
+
* The returned rows will be unique on a per dev/prod app basis.
|
|
47
|
+
* Rows duplicates may exist across apps due to data import so they are not filtered out.
|
|
48
|
+
*/
|
|
49
|
+
exports.getUniqueRows = async appIds => {
|
|
50
|
+
let uniqueRows = []
|
|
51
|
+
const pairs = getAppPairs(appIds)
|
|
52
|
+
|
|
53
|
+
for (let pair of Object.values(pairs)) {
|
|
54
|
+
let appRows = []
|
|
55
|
+
for (let appId of [pair.devId, pair.prodId]) {
|
|
56
|
+
if (!appId) {
|
|
57
|
+
continue
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
appRows.push(await getAppRows(appId))
|
|
61
|
+
} catch (e) {
|
|
62
|
+
console.error(e)
|
|
63
|
+
// don't error out if we can't count the app rows, just continue
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ensure uniqueness on a per app pair basis
|
|
68
|
+
// this can't be done on all rows because app import results in
|
|
69
|
+
// duplicate row ids across apps
|
|
70
|
+
uniqueRows = uniqueRows.concat(...new Set(appRows))
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return uniqueRows
|
|
74
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// UNUSED CODE
|
|
2
|
+
// Preserved for future use
|
|
3
|
+
|
|
4
|
+
/* eslint-disable no-unused-vars */
|
|
5
|
+
|
|
6
|
+
function getNewQuotaReset() {
|
|
7
|
+
return Date.now() + 2592000000
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function resetQuotasIfRequired(quota) {
|
|
11
|
+
// Check if the quota needs reset
|
|
12
|
+
if (Date.now() >= quota.quotaReset) {
|
|
13
|
+
quota.quotaReset = getNewQuotaReset()
|
|
14
|
+
for (let prop of Object.keys(quota.usageQuota)) {
|
|
15
|
+
quota.usageQuota[prop] = 0
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -58,29 +58,6 @@ exports.sendSmtpEmail = async (to, from, subject, contents, automation) => {
|
|
|
58
58
|
return response.json()
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
exports.getDeployedApps = async () => {
|
|
62
|
-
try {
|
|
63
|
-
const response = await fetch(
|
|
64
|
-
checkSlashesInUrl(env.WORKER_URL + `/api/apps`),
|
|
65
|
-
request(null, {
|
|
66
|
-
method: "GET",
|
|
67
|
-
})
|
|
68
|
-
)
|
|
69
|
-
const json = await 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
|
-
} catch (err) {
|
|
79
|
-
// error, cannot determine deployed apps, don't stop app creation - sort this later
|
|
80
|
-
return {}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
61
|
exports.getGlobalSelf = async (ctx, appId = null) => {
|
|
85
62
|
const endpoint = `/api/global/users/self`
|
|
86
63
|
const response = await fetch(
|