@budibase/server 2.0.33 → 2.0.34-alpha.0
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/__mocks__/mongodb.ts +1 -1
- package/builder/assets/backups-default.8c011f1b.png +0 -0
- package/builder/assets/{index.dfa4073c.css → index.b15ffe95.css} +2 -2
- package/builder/assets/{index.ce49a649.js → index.d09d1931.js} +340 -332
- package/builder/index.html +2 -2
- package/coverage/clover.xml +634 -689
- package/coverage/coverage-final.json +34 -36
- package/coverage/lcov-report/api/controllers/apikeys.js.html +1 -1
- package/coverage/lcov-report/api/controllers/automation.js.html +1 -1
- package/coverage/lcov-report/api/controllers/cloud.js.html +74 -62
- package/coverage/lcov-report/api/controllers/datasource.js.html +1 -1
- package/coverage/lcov-report/api/controllers/dev.js.html +2 -2
- package/coverage/lcov-report/api/controllers/index.html +17 -32
- package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
- package/coverage/lcov-report/api/controllers/layout.js.html +1 -1
- package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
- package/coverage/lcov-report/api/controllers/migrations.js.html +1 -1
- package/coverage/lcov-report/api/controllers/permission.js.html +1 -1
- package/coverage/lcov-report/api/controllers/query/index.html +1 -1
- package/coverage/lcov-report/api/controllers/query/validation.js.html +1 -1
- package/coverage/lcov-report/api/controllers/role.js.html +1 -1
- package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/external.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/index.html +1 -1
- package/coverage/lcov-report/api/controllers/row/internal.js.html +12 -12
- package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/staticFormula.js.html +15 -15
- package/coverage/lcov-report/api/controllers/row/utils.js.html +13 -13
- package/coverage/lcov-report/api/controllers/script.js.html +1 -1
- package/coverage/lcov-report/api/controllers/table/bulkFormula.js.html +12 -9
- package/coverage/lcov-report/api/controllers/table/external.js.html +10 -10
- package/coverage/lcov-report/api/controllers/table/index.html +16 -16
- package/coverage/lcov-report/api/controllers/table/index.js.html +5 -5
- package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
- package/coverage/lcov-report/api/controllers/user.js.html +1 -1
- package/coverage/lcov-report/api/controllers/view/exporters.js.html +1 -1
- package/coverage/lcov-report/api/controllers/view/index.html +1 -1
- package/coverage/lcov-report/api/controllers/view/index.js.html +3 -3
- package/coverage/lcov-report/api/controllers/view/utils.js.html +1 -1
- package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +1 -1
- package/coverage/lcov-report/api/controllers/webhook.js.html +1 -1
- package/coverage/lcov-report/api/index.html +1 -1
- package/coverage/lcov-report/api/index.js.html +7 -7
- 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/automation.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 +5 -20
- 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/migrations.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/screen.js.html +1 -1
- package/coverage/lcov-report/api/routes/script.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/utils/index.html +1 -1
- package/coverage/lcov-report/api/routes/utils/validators.js.html +1 -1
- package/coverage/lcov-report/api/routes/view.js.html +1 -1
- package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
- package/coverage/lcov-report/automations/actions.js.html +1 -1
- package/coverage/lcov-report/automations/automationUtils.js.html +6 -6
- package/coverage/lcov-report/automations/bullboard.js.html +17 -92
- package/coverage/lcov-report/automations/index.html +18 -18
- package/coverage/lcov-report/automations/index.js.html +9 -9
- package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
- package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
- package/coverage/lcov-report/automations/steps/discord.js.html +1 -1
- package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
- package/coverage/lcov-report/automations/steps/executeScript.js.html +1 -1
- package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
- package/coverage/lcov-report/automations/steps/index.html +1 -1
- package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
- package/coverage/lcov-report/automations/steps/loop.js.html +1 -1
- package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +1 -1
- package/coverage/lcov-report/automations/steps/queryRows.js.html +1 -1
- package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
- package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
- package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
- package/coverage/lcov-report/automations/steps/updateRow.js.html +3 -3
- package/coverage/lcov-report/automations/steps/utils.js.html +1 -1
- package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/app.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/cron.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/index.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +1 -1
- package/coverage/lcov-report/automations/triggers.js.html +26 -26
- package/coverage/lcov-report/constants/index.html +5 -5
- package/coverage/lcov-report/constants/index.js.html +10 -16
- package/coverage/lcov-report/constants/layouts.js.html +1 -1
- package/coverage/lcov-report/constants/screens.js.html +1 -1
- package/coverage/lcov-report/db/inMemoryView.js.html +1 -1
- package/coverage/lcov-report/db/index.html +19 -19
- package/coverage/lcov-report/db/index.js.html +1 -1
- package/coverage/lcov-report/db/linkedRows/LinkController.js.html +11 -11
- package/coverage/lcov-report/db/linkedRows/index.html +1 -1
- package/coverage/lcov-report/db/linkedRows/index.js.html +11 -11
- package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +3 -3
- package/coverage/lcov-report/db/newid.js.html +2 -2
- package/coverage/lcov-report/db/utils.js.html +37 -316
- 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 +2 -2
- package/coverage/lcov-report/events/utils.js.html +9 -9
- package/coverage/lcov-report/index.html +77 -77
- 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/builder.js.html +11 -11
- package/coverage/lcov-report/middleware/currentapp.js.html +34 -34
- package/coverage/lcov-report/middleware/index.html +1 -1
- package/coverage/lcov-report/middleware/joi-validator.js.html +1 -1
- package/coverage/lcov-report/middleware/publicApi.js.html +1 -1
- package/coverage/lcov-report/middleware/resourceId.js.html +7 -7
- package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
- package/coverage/lcov-report/middleware/utils.js.html +2 -2
- package/coverage/lcov-report/utilities/budibaseDir.js.html +1 -1
- package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
- package/coverage/lcov-report/utilities/csvParser.js.html +11 -8
- package/coverage/lcov-report/utilities/global.js.html +16 -16
- package/coverage/lcov-report/utilities/index.html +15 -15
- package/coverage/lcov-report/utilities/index.js.html +7 -7
- package/coverage/lcov-report/utilities/plugins.js.html +1 -1
- package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +52 -52
- package/coverage/lcov-report/utilities/queue/index.html +21 -21
- 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 +54 -39
- package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +10 -10
- package/coverage/lcov-report/utilities/scriptRunner.js.html +1 -1
- package/coverage/lcov-report/utilities/security.js.html +2 -2
- package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
- package/coverage/lcov-report/utilities/usageQuota/index.html +14 -14
- package/coverage/lcov-report/utilities/usageQuota/rows.js.html +23 -11
- package/coverage/lcov-report/utilities/usageQuota/usageQuoteReset.js.html +1 -1
- package/coverage/lcov-report/utilities/users.js.html +1 -1
- package/coverage/lcov-report/utilities/workerRequests.js.html +1 -1
- package/coverage/lcov.info +1141 -1246
- package/dist/api/controllers/application.js +4 -7
- package/dist/api/controllers/backup.js +19 -13
- package/dist/api/controllers/cloud.js +38 -35
- package/dist/api/controllers/deploy/index.js +11 -2
- package/dist/api/controllers/dev.js +1 -1
- package/dist/api/controllers/query/index.js +7 -2
- package/dist/api/controllers/row/index.js +30 -10
- package/dist/api/controllers/static/index.js +2 -2
- package/dist/api/controllers/static/templates/preview.hbs +10 -0
- package/dist/api/controllers/table/bulkFormula.js +4 -3
- package/dist/api/controllers/table/external.js +5 -4
- package/dist/api/controllers/table/index.js +4 -4
- package/dist/api/controllers/table/internal.js +10 -3
- package/dist/api/controllers/table/utils.js +7 -49
- package/dist/api/controllers/view/index.js +2 -2
- package/dist/api/routes/backup.js +34 -7
- package/dist/api/routes/index.js +9 -4
- package/dist/app.js +14 -0
- package/dist/automations/automationUtils.js +2 -2
- package/dist/automations/bullboard.js +5 -33
- package/dist/automations/index.js +4 -4
- package/dist/automations/steps/updateRow.js +2 -2
- package/dist/automations/triggers.js +4 -4
- package/dist/automations/utils.js +18 -12
- package/dist/constants/index.js +4 -5
- package/dist/db/utils.js +10 -75
- package/dist/index.js +1 -0
- package/dist/integrations/arangodb.js +2 -0
- package/dist/integrations/base/sqlTable.js +1 -0
- package/dist/integrations/mongodb.js +300 -11
- package/dist/integrations/rest.js +38 -5
- package/dist/migrations/functions/backfill/app/tables.js +5 -8
- package/dist/migrations/functions/{quotas1.js → syncQuotas.js} +3 -7
- package/dist/migrations/functions/usageQuotas/syncApps.js +0 -1
- package/dist/migrations/functions/{pluginCount.js → usageQuotas/syncPlugins.js} +1 -3
- package/dist/migrations/functions/usageQuotas/syncRows.js +9 -5
- package/dist/migrations/index.js +9 -38
- package/dist/package.json +14 -14
- package/dist/sdk/app/backups/constants.js +5 -0
- package/dist/sdk/app/backups/exports.js +172 -0
- package/dist/sdk/app/backups/imports.js +162 -0
- package/dist/sdk/app/backups/index.js +29 -0
- package/dist/sdk/app/backups/statistics.js +73 -0
- package/dist/sdk/app/tables/index.js +61 -0
- package/dist/sdk/index.js +15 -0
- package/dist/tests/utilities/TestConfiguration.js +4 -2
- package/dist/threads/automation.js +12 -17
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/utilities/csvParser.js +1 -0
- package/dist/utilities/fileSystem/index.js +3 -95
- package/dist/utilities/fileSystem/utilities.js +2 -1
- package/dist/utilities/rowProcessor/index.js +5 -0
- package/dist/utilities/usageQuota/rows.js +6 -4
- package/package.json +15 -15
- package/specs/openapi.json +3 -0
- package/specs/openapi.yaml +3 -0
- package/src/api/controllers/application.ts +5 -12
- package/src/api/controllers/{backup.js → backup.ts} +7 -7
- package/src/api/controllers/cloud.js +44 -40
- package/src/api/controllers/deploy/index.ts +20 -8
- package/src/api/controllers/dev.js +1 -1
- package/src/api/controllers/query/index.ts +8 -2
- package/src/api/controllers/row/index.ts +36 -13
- package/src/api/controllers/static/index.ts +2 -2
- package/src/api/controllers/static/templates/preview.hbs +10 -0
- package/src/api/controllers/table/bulkFormula.js +4 -3
- package/src/api/controllers/table/external.js +4 -4
- package/src/api/controllers/table/index.js +4 -4
- package/src/api/controllers/table/internal.ts +8 -9
- package/src/api/controllers/table/utils.ts +4 -53
- package/src/api/controllers/view/index.js +2 -2
- package/src/api/routes/backup.ts +10 -0
- package/src/api/routes/index.ts +11 -5
- package/src/api/routes/tests/backup.spec.js +1 -1
- package/src/api/routes/tests/{deployment.spec.js → deployment.spec.ts} +4 -4
- package/src/api/routes/tests/row.spec.js +22 -27
- package/src/app.ts +15 -0
- package/src/automations/automationUtils.js +2 -2
- package/src/automations/bullboard.js +8 -33
- package/src/automations/index.js +4 -4
- package/src/automations/steps/updateRow.js +2 -2
- package/src/automations/tests/automation.spec.js +1 -6
- package/src/automations/triggers.js +4 -4
- package/src/automations/utils.ts +18 -12
- package/src/constants/index.js +4 -6
- package/src/db/utils.js +17 -110
- package/src/definitions/automations.ts +0 -12
- package/src/definitions/datasource.ts +1 -0
- package/src/index.ts +1 -0
- package/src/integrations/arangodb.ts +2 -0
- package/src/integrations/base/sqlTable.ts +1 -0
- package/src/integrations/mongodb.ts +290 -27
- package/src/integrations/rest.ts +17 -5
- package/src/integrations/tests/mongo.spec.ts +19 -19
- package/src/integrations/tests/rest.spec.ts +38 -22
- package/src/migrations/functions/backfill/app/tables.ts +7 -13
- package/src/migrations/functions/backfill/global.ts +1 -1
- package/src/migrations/functions/{quotas1.ts → syncQuotas.ts} +3 -8
- package/src/migrations/functions/tests/{quotas1.spec.js → syncQuotas.spec.js} +5 -2
- package/src/migrations/functions/usageQuotas/syncApps.ts +0 -1
- package/src/migrations/functions/usageQuotas/syncPlugins.ts +10 -0
- package/src/migrations/functions/usageQuotas/syncRows.ts +15 -6
- package/src/migrations/functions/usageQuotas/tests/syncRows.spec.ts +9 -1
- package/src/migrations/index.ts +20 -45
- package/src/migrations/tests/index.spec.ts +0 -1
- package/src/sdk/app/backups/constants.ts +2 -0
- package/src/sdk/app/backups/exports.ts +171 -0
- package/src/sdk/app/backups/imports.ts +169 -0
- package/src/sdk/app/backups/index.ts +9 -0
- package/src/sdk/app/backups/statistics.ts +78 -0
- package/src/sdk/app/tables/index.ts +61 -0
- package/src/sdk/index.ts +13 -0
- package/src/tests/utilities/TestConfiguration.js +5 -2
- package/src/threads/automation.ts +20 -27
- package/src/utilities/csvParser.js +1 -0
- package/src/utilities/fileSystem/index.js +2 -119
- package/src/utilities/fileSystem/utilities.js +2 -0
- package/src/utilities/rowProcessor/index.js +5 -0
- package/src/utilities/usageQuota/rows.js +7 -3
- package/coverage/lcov-report/api/controllers/backup.js.html +0 -142
- package/coverage/lcov-report/api/routes/backup.js.html +0 -115
- package/dist/automations/listeners.js +0 -102
- package/src/api/routes/backup.js +0 -10
- package/src/automations/listeners.ts +0 -78
- package/src/migrations/functions/pluginCount.ts +0 -12
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { db as dbCore } from "@budibase/backend-core"
|
|
2
|
+
import { TABLE_ROW_PREFIX } from "../../../db/utils"
|
|
3
|
+
import { budibaseTempDir } from "../../../utilities/budibaseDir"
|
|
4
|
+
import { DB_EXPORT_FILE, GLOBAL_DB_EXPORT_FILE } from "./constants"
|
|
5
|
+
import {
|
|
6
|
+
uploadDirectory,
|
|
7
|
+
upload,
|
|
8
|
+
} from "../../../utilities/fileSystem/utilities"
|
|
9
|
+
import { downloadTemplate } from "../../../utilities/fileSystem"
|
|
10
|
+
import { ObjectStoreBuckets, FieldTypes } from "../../../constants"
|
|
11
|
+
import { join } from "path"
|
|
12
|
+
import fs from "fs"
|
|
13
|
+
import sdk from "../../"
|
|
14
|
+
import { CouchFindOptions, RowAttachment } from "@budibase/types"
|
|
15
|
+
const uuid = require("uuid/v4")
|
|
16
|
+
const tar = require("tar")
|
|
17
|
+
import PouchDB from "pouchdb"
|
|
18
|
+
|
|
19
|
+
type TemplateType = {
|
|
20
|
+
file?: {
|
|
21
|
+
type: string
|
|
22
|
+
path: string
|
|
23
|
+
}
|
|
24
|
+
key?: string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function updateAttachmentColumns(
|
|
28
|
+
prodAppId: string,
|
|
29
|
+
db: PouchDB.Database
|
|
30
|
+
) {
|
|
31
|
+
// iterate through attachment documents and update them
|
|
32
|
+
const tables = await sdk.tables.getAllInternalTables(db)
|
|
33
|
+
for (let table of tables) {
|
|
34
|
+
const attachmentCols: string[] = []
|
|
35
|
+
for (let [key, column] of Object.entries(table.schema)) {
|
|
36
|
+
if (column.type === FieldTypes.ATTACHMENT) {
|
|
37
|
+
attachmentCols.push(key)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// no attachment columns, nothing to do
|
|
41
|
+
if (attachmentCols.length === 0) {
|
|
42
|
+
continue
|
|
43
|
+
}
|
|
44
|
+
// use the CouchDB Mango query API to lookup rows that have attachments
|
|
45
|
+
const params: CouchFindOptions = {
|
|
46
|
+
selector: {
|
|
47
|
+
_id: {
|
|
48
|
+
$regex: `^${TABLE_ROW_PREFIX}`,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
}
|
|
52
|
+
attachmentCols.forEach(col => (params.selector[col] = { $exists: true }))
|
|
53
|
+
const { rows } = await dbCore.directCouchFind(db.name, params)
|
|
54
|
+
for (let row of rows) {
|
|
55
|
+
for (let column of attachmentCols) {
|
|
56
|
+
if (!Array.isArray(row[column])) {
|
|
57
|
+
continue
|
|
58
|
+
}
|
|
59
|
+
row[column] = row[column].map((attachment: RowAttachment) => {
|
|
60
|
+
// URL looks like: /prod-budi-app-assets/appId/attachments/file.csv
|
|
61
|
+
const urlParts = attachment.url.split("/")
|
|
62
|
+
// drop the first empty element
|
|
63
|
+
urlParts.shift()
|
|
64
|
+
// get the prefix
|
|
65
|
+
const prefix = urlParts.shift()
|
|
66
|
+
// remove the app ID
|
|
67
|
+
urlParts.shift()
|
|
68
|
+
// add new app ID
|
|
69
|
+
urlParts.unshift(prodAppId)
|
|
70
|
+
const key = urlParts.join("/")
|
|
71
|
+
return {
|
|
72
|
+
...attachment,
|
|
73
|
+
key,
|
|
74
|
+
url: `/${prefix}/${key}`,
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// write back the updated attachments
|
|
80
|
+
await db.bulkDocs(rows)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* This function manages temporary template files which are stored by Koa.
|
|
86
|
+
* @param {Object} template The template object retrieved from the Koa context object.
|
|
87
|
+
* @returns {Object} Returns a fs read stream which can be loaded into the database.
|
|
88
|
+
*/
|
|
89
|
+
async function getTemplateStream(template: TemplateType) {
|
|
90
|
+
if (template.file) {
|
|
91
|
+
return fs.createReadStream(template.file.path)
|
|
92
|
+
} else if (template.key) {
|
|
93
|
+
const [type, name] = template.key.split("/")
|
|
94
|
+
const tmpPath = await downloadTemplate(type, name)
|
|
95
|
+
return fs.createReadStream(join(tmpPath, name, "db", "dump.txt"))
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function untarFile(file: { path: string }) {
|
|
100
|
+
const tmpPath = join(budibaseTempDir(), uuid())
|
|
101
|
+
fs.mkdirSync(tmpPath)
|
|
102
|
+
// extract the tarball
|
|
103
|
+
tar.extract({
|
|
104
|
+
sync: true,
|
|
105
|
+
cwd: tmpPath,
|
|
106
|
+
file: file.path,
|
|
107
|
+
})
|
|
108
|
+
return tmpPath
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function getGlobalDBFile(tmpPath: string) {
|
|
112
|
+
return fs.readFileSync(join(tmpPath, GLOBAL_DB_EXPORT_FILE), "utf8")
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function getListOfAppsInMulti(tmpPath: string) {
|
|
116
|
+
return fs.readdirSync(tmpPath).filter(dir => dir !== GLOBAL_DB_EXPORT_FILE)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export async function importApp(
|
|
120
|
+
appId: string,
|
|
121
|
+
db: PouchDB.Database,
|
|
122
|
+
template: TemplateType
|
|
123
|
+
) {
|
|
124
|
+
let prodAppId = dbCore.getProdAppID(appId)
|
|
125
|
+
let dbStream: any
|
|
126
|
+
const isTar = template.file && template.file.type === "application/gzip"
|
|
127
|
+
const isDirectory =
|
|
128
|
+
template.file && fs.lstatSync(template.file.path).isDirectory()
|
|
129
|
+
if (template.file && (isTar || isDirectory)) {
|
|
130
|
+
const tmpPath = isTar ? untarFile(template.file) : template.file.path
|
|
131
|
+
const contents = fs.readdirSync(tmpPath)
|
|
132
|
+
// have to handle object import
|
|
133
|
+
if (contents.length) {
|
|
134
|
+
let promises = []
|
|
135
|
+
let excludedFiles = [GLOBAL_DB_EXPORT_FILE, DB_EXPORT_FILE]
|
|
136
|
+
for (let filename of contents) {
|
|
137
|
+
const path = join(tmpPath, filename)
|
|
138
|
+
if (excludedFiles.includes(filename)) {
|
|
139
|
+
continue
|
|
140
|
+
}
|
|
141
|
+
filename = join(prodAppId, filename)
|
|
142
|
+
if (fs.lstatSync(path).isDirectory()) {
|
|
143
|
+
promises.push(
|
|
144
|
+
uploadDirectory(ObjectStoreBuckets.APPS, path, filename)
|
|
145
|
+
)
|
|
146
|
+
} else {
|
|
147
|
+
promises.push(
|
|
148
|
+
upload({
|
|
149
|
+
bucket: ObjectStoreBuckets.APPS,
|
|
150
|
+
path,
|
|
151
|
+
filename,
|
|
152
|
+
})
|
|
153
|
+
)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
await Promise.all(promises)
|
|
157
|
+
}
|
|
158
|
+
dbStream = fs.createReadStream(join(tmpPath, DB_EXPORT_FILE))
|
|
159
|
+
} else {
|
|
160
|
+
dbStream = await getTemplateStream(template)
|
|
161
|
+
}
|
|
162
|
+
// @ts-ignore
|
|
163
|
+
const { ok } = await db.load(dbStream)
|
|
164
|
+
if (!ok) {
|
|
165
|
+
throw "Error loading database dump from template."
|
|
166
|
+
}
|
|
167
|
+
await updateAttachmentColumns(prodAppId, db)
|
|
168
|
+
return ok
|
|
169
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { context, db as dbCore } from "@budibase/backend-core"
|
|
2
|
+
import {
|
|
3
|
+
getDatasourceParams,
|
|
4
|
+
getTableParams,
|
|
5
|
+
getAutomationParams,
|
|
6
|
+
getScreenParams,
|
|
7
|
+
} from "../../../db/utils"
|
|
8
|
+
import PouchDB from "pouchdb"
|
|
9
|
+
|
|
10
|
+
async function runInContext(appId: string, cb: any, db?: PouchDB.Database) {
|
|
11
|
+
if (db) {
|
|
12
|
+
return cb(db)
|
|
13
|
+
} else {
|
|
14
|
+
const devAppId = dbCore.getDevAppID(appId)
|
|
15
|
+
return context.doInAppContext(devAppId, () => {
|
|
16
|
+
const db = context.getAppDB()
|
|
17
|
+
return cb(db)
|
|
18
|
+
})
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function calculateDatasourceCount(
|
|
23
|
+
appId: string,
|
|
24
|
+
db?: PouchDB.Database
|
|
25
|
+
) {
|
|
26
|
+
return runInContext(
|
|
27
|
+
appId,
|
|
28
|
+
async (db: PouchDB.Database) => {
|
|
29
|
+
const datasourceList = await db.allDocs(getDatasourceParams())
|
|
30
|
+
const tableList = await db.allDocs(getTableParams())
|
|
31
|
+
return datasourceList.rows.length + tableList.rows.length
|
|
32
|
+
},
|
|
33
|
+
db
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function calculateAutomationCount(
|
|
38
|
+
appId: string,
|
|
39
|
+
db?: PouchDB.Database
|
|
40
|
+
) {
|
|
41
|
+
return runInContext(
|
|
42
|
+
appId,
|
|
43
|
+
async (db: PouchDB.Database) => {
|
|
44
|
+
const automationList = await db.allDocs(getAutomationParams())
|
|
45
|
+
return automationList.rows.length
|
|
46
|
+
},
|
|
47
|
+
db
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export async function calculateScreenCount(
|
|
52
|
+
appId: string,
|
|
53
|
+
db?: PouchDB.Database
|
|
54
|
+
) {
|
|
55
|
+
return runInContext(
|
|
56
|
+
appId,
|
|
57
|
+
async (db: PouchDB.Database) => {
|
|
58
|
+
const screenList = await db.allDocs(getScreenParams())
|
|
59
|
+
return screenList.rows.length
|
|
60
|
+
},
|
|
61
|
+
db
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export async function calculateBackupStats(appId: string) {
|
|
66
|
+
return runInContext(appId, async (db: PouchDB.Database) => {
|
|
67
|
+
const promises = []
|
|
68
|
+
promises.push(calculateDatasourceCount(appId, db))
|
|
69
|
+
promises.push(calculateAutomationCount(appId, db))
|
|
70
|
+
promises.push(calculateScreenCount(appId, db))
|
|
71
|
+
const responses = await Promise.all(promises)
|
|
72
|
+
return {
|
|
73
|
+
datasources: responses[0],
|
|
74
|
+
automations: responses[1],
|
|
75
|
+
screens: responses[2],
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { getAppDB } from "@budibase/backend-core/context"
|
|
2
|
+
import { BudibaseInternalDB, getTableParams } from "../../../db/utils"
|
|
3
|
+
import {
|
|
4
|
+
breakExternalTableId,
|
|
5
|
+
isExternalTable,
|
|
6
|
+
isSQL,
|
|
7
|
+
} from "../../../integrations/utils"
|
|
8
|
+
import { Table } from "@budibase/types"
|
|
9
|
+
import PouchDB from "pouchdb"
|
|
10
|
+
|
|
11
|
+
async function getAllInternalTables(db?: PouchDB.Database): Promise<Table[]> {
|
|
12
|
+
if (!db) {
|
|
13
|
+
db = getAppDB() as PouchDB.Database
|
|
14
|
+
}
|
|
15
|
+
const internalTables = await db.allDocs(
|
|
16
|
+
getTableParams(null, {
|
|
17
|
+
include_docs: true,
|
|
18
|
+
})
|
|
19
|
+
)
|
|
20
|
+
return internalTables.rows.map((tableDoc: any) => ({
|
|
21
|
+
...tableDoc.doc,
|
|
22
|
+
type: "internal",
|
|
23
|
+
sourceId: BudibaseInternalDB._id,
|
|
24
|
+
}))
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function getAllExternalTables(datasourceId: any): Promise<Table[]> {
|
|
28
|
+
const db = getAppDB()
|
|
29
|
+
const datasource = await db.get(datasourceId)
|
|
30
|
+
if (!datasource || !datasource.entities) {
|
|
31
|
+
throw "Datasource is not configured fully."
|
|
32
|
+
}
|
|
33
|
+
return datasource.entities
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function getExternalTable(
|
|
37
|
+
datasourceId: any,
|
|
38
|
+
tableName: any
|
|
39
|
+
): Promise<Table> {
|
|
40
|
+
const entities = await getAllExternalTables(datasourceId)
|
|
41
|
+
return entities[tableName]
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function getTable(tableId: any): Promise<Table> {
|
|
45
|
+
const db = getAppDB()
|
|
46
|
+
if (isExternalTable(tableId)) {
|
|
47
|
+
let { datasourceId, tableName } = breakExternalTableId(tableId)
|
|
48
|
+
const datasource = await db.get(datasourceId)
|
|
49
|
+
const table = await getExternalTable(datasourceId, tableName)
|
|
50
|
+
return { ...table, sql: isSQL(datasource) }
|
|
51
|
+
} else {
|
|
52
|
+
return db.get(tableId)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export default {
|
|
57
|
+
getAllInternalTables,
|
|
58
|
+
getAllExternalTables,
|
|
59
|
+
getExternalTable,
|
|
60
|
+
getTable,
|
|
61
|
+
}
|
package/src/sdk/index.ts
ADDED
|
@@ -25,7 +25,7 @@ const newid = require("../../db/newid")
|
|
|
25
25
|
const context = require("@budibase/backend-core/context")
|
|
26
26
|
const { generateDevInfoID, SEPARATOR } = require("@budibase/backend-core/db")
|
|
27
27
|
const { encrypt } = require("@budibase/backend-core/encryption")
|
|
28
|
-
const { DocumentType } = require("../../db/utils")
|
|
28
|
+
const { DocumentType, generateUserMetadataID } = require("../../db/utils")
|
|
29
29
|
|
|
30
30
|
const GLOBAL_USER_ID = "us_uuid1"
|
|
31
31
|
const EMAIL = "babs@babs.com"
|
|
@@ -95,7 +95,10 @@ class TestConfiguration {
|
|
|
95
95
|
|
|
96
96
|
// use a new id as the name to avoid name collisions
|
|
97
97
|
async init(appName = newid()) {
|
|
98
|
-
await this.globalUser()
|
|
98
|
+
this.user = await this.globalUser()
|
|
99
|
+
this.globalUserId = this.user._id
|
|
100
|
+
this.userMetadataId = generateUserMetadataID(this.globalUserId)
|
|
101
|
+
|
|
99
102
|
return this.createApp(appName)
|
|
100
103
|
}
|
|
101
104
|
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { default as threadUtils } from "./utils"
|
|
2
|
+
import { Job } from "bull"
|
|
2
3
|
threadUtils.threadSetup()
|
|
3
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
isRecurring,
|
|
6
|
+
disableCronById,
|
|
7
|
+
isErrorInOutput,
|
|
8
|
+
} from "../automations/utils"
|
|
4
9
|
import { default as actions } from "../automations/actions"
|
|
5
10
|
import { default as automationUtils } from "../automations/automationUtils"
|
|
6
11
|
import { default as AutomationEmitter } from "../events/AutomationEmitter"
|
|
@@ -13,7 +18,6 @@ import {
|
|
|
13
18
|
LoopStep,
|
|
14
19
|
LoopStepType,
|
|
15
20
|
LoopInput,
|
|
16
|
-
AutomationEvent,
|
|
17
21
|
TriggerOutput,
|
|
18
22
|
AutomationContext,
|
|
19
23
|
AutomationMetadata,
|
|
@@ -73,19 +77,16 @@ class Orchestrator {
|
|
|
73
77
|
_automation: Automation
|
|
74
78
|
_emitter: any
|
|
75
79
|
_context: AutomationContext
|
|
76
|
-
|
|
80
|
+
_job: Job
|
|
77
81
|
executionOutput: AutomationContext
|
|
78
82
|
|
|
79
|
-
constructor(
|
|
83
|
+
constructor(job: Job) {
|
|
84
|
+
let automation = job.data.automation,
|
|
85
|
+
triggerOutput = job.data.event
|
|
80
86
|
const metadata = triggerOutput.metadata
|
|
81
87
|
this._chainCount = metadata ? metadata.automationChainCount : 0
|
|
82
88
|
this._appId = triggerOutput.appId as string
|
|
83
|
-
|
|
84
|
-
this._repeat = {
|
|
85
|
-
jobId: opts.repeat.jobId,
|
|
86
|
-
jobKey: opts.repeat.key,
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
+
this._job = job
|
|
89
90
|
const triggerStepId = automation.definition.trigger.stepId
|
|
90
91
|
triggerOutput = this.cleanupTriggerOutputs(triggerStepId, triggerOutput)
|
|
91
92
|
// remove from context
|
|
@@ -134,7 +135,7 @@ class Orchestrator {
|
|
|
134
135
|
}
|
|
135
136
|
|
|
136
137
|
async stopCron(reason: string) {
|
|
137
|
-
if (!this.
|
|
138
|
+
if (!this._job.opts.repeat) {
|
|
138
139
|
return
|
|
139
140
|
}
|
|
140
141
|
logWarn(
|
|
@@ -142,7 +143,7 @@ class Orchestrator {
|
|
|
142
143
|
)
|
|
143
144
|
const automation = this._automation
|
|
144
145
|
const trigger = automation.definition.trigger
|
|
145
|
-
await
|
|
146
|
+
await disableCronById(this._job.id)
|
|
146
147
|
this.updateExecutionOutput(
|
|
147
148
|
trigger.id,
|
|
148
149
|
trigger.stepId,
|
|
@@ -156,7 +157,7 @@ class Orchestrator {
|
|
|
156
157
|
}
|
|
157
158
|
|
|
158
159
|
async checkIfShouldStop(metadata: AutomationMetadata): Promise<boolean> {
|
|
159
|
-
if (!metadata.errorCount || !this.
|
|
160
|
+
if (!metadata.errorCount || !this._job.opts.repeat) {
|
|
160
161
|
return false
|
|
161
162
|
}
|
|
162
163
|
if (metadata.errorCount >= MAX_AUTOMATION_RECURRING_ERRORS) {
|
|
@@ -475,17 +476,13 @@ class Orchestrator {
|
|
|
475
476
|
}
|
|
476
477
|
}
|
|
477
478
|
|
|
478
|
-
export function execute(
|
|
479
|
-
const appId =
|
|
479
|
+
export function execute(job: Job, callback: WorkerCallback) {
|
|
480
|
+
const appId = job.data.event.appId
|
|
480
481
|
if (!appId) {
|
|
481
482
|
throw new Error("Unable to execute, event doesn't contain app ID.")
|
|
482
483
|
}
|
|
483
484
|
doInAppContext(appId, async () => {
|
|
484
|
-
const automationOrchestrator = new Orchestrator(
|
|
485
|
-
input.data.automation,
|
|
486
|
-
input.data.event,
|
|
487
|
-
input.opts
|
|
488
|
-
)
|
|
485
|
+
const automationOrchestrator = new Orchestrator(job)
|
|
489
486
|
try {
|
|
490
487
|
const response = await automationOrchestrator.execute()
|
|
491
488
|
callback(null, response)
|
|
@@ -495,17 +492,13 @@ export function execute(input: AutomationEvent, callback: WorkerCallback) {
|
|
|
495
492
|
})
|
|
496
493
|
}
|
|
497
494
|
|
|
498
|
-
export const removeStalled = async (
|
|
499
|
-
const appId =
|
|
495
|
+
export const removeStalled = async (job: Job) => {
|
|
496
|
+
const appId = job.data.event.appId
|
|
500
497
|
if (!appId) {
|
|
501
498
|
throw new Error("Unable to execute, event doesn't contain app ID.")
|
|
502
499
|
}
|
|
503
500
|
await doInAppContext(appId, async () => {
|
|
504
|
-
const automationOrchestrator = new Orchestrator(
|
|
505
|
-
input.data.automation,
|
|
506
|
-
input.data.event,
|
|
507
|
-
input.opts
|
|
508
|
-
)
|
|
501
|
+
const automationOrchestrator = new Orchestrator(job)
|
|
509
502
|
await automationOrchestrator.stopCron("stalled")
|
|
510
503
|
})
|
|
511
504
|
}
|
|
@@ -2,17 +2,11 @@ const { budibaseTempDir } = require("../budibaseDir")
|
|
|
2
2
|
const fs = require("fs")
|
|
3
3
|
const { join } = require("path")
|
|
4
4
|
const uuid = require("uuid/v4")
|
|
5
|
-
const {
|
|
6
|
-
doWithDB,
|
|
7
|
-
dangerousGetDB,
|
|
8
|
-
closeDB,
|
|
9
|
-
} = require("@budibase/backend-core/db")
|
|
10
5
|
const { ObjectStoreBuckets } = require("../../constants")
|
|
11
6
|
const {
|
|
12
7
|
upload,
|
|
13
8
|
retrieve,
|
|
14
9
|
retrieveToTmp,
|
|
15
|
-
streamUpload,
|
|
16
10
|
deleteFolder,
|
|
17
11
|
downloadTarball,
|
|
18
12
|
downloadTarballDirect,
|
|
@@ -21,12 +15,6 @@ const {
|
|
|
21
15
|
const { updateClientLibrary } = require("./clientLibrary")
|
|
22
16
|
const { checkSlashesInUrl } = require("../")
|
|
23
17
|
const env = require("../../environment")
|
|
24
|
-
const {
|
|
25
|
-
USER_METDATA_PREFIX,
|
|
26
|
-
LINK_USER_METADATA_PREFIX,
|
|
27
|
-
TABLE_ROW_PREFIX,
|
|
28
|
-
} = require("../../db/utils")
|
|
29
|
-
const MemoryStream = require("memorystream")
|
|
30
18
|
const { getAppId } = require("@budibase/backend-core/context")
|
|
31
19
|
const tar = require("tar")
|
|
32
20
|
const fetch = require("node-fetch")
|
|
@@ -86,21 +74,6 @@ exports.checkDevelopmentEnvironment = () => {
|
|
|
86
74
|
}
|
|
87
75
|
}
|
|
88
76
|
|
|
89
|
-
/**
|
|
90
|
-
* This function manages temporary template files which are stored by Koa.
|
|
91
|
-
* @param {Object} template The template object retrieved from the Koa context object.
|
|
92
|
-
* @returns {Object} Returns an fs read stream which can be loaded into the database.
|
|
93
|
-
*/
|
|
94
|
-
exports.getTemplateStream = async template => {
|
|
95
|
-
if (template.file) {
|
|
96
|
-
return fs.createReadStream(template.file.path)
|
|
97
|
-
} else {
|
|
98
|
-
const [type, name] = template.key.split("/")
|
|
99
|
-
const tmpPath = await exports.downloadTemplate(type, name)
|
|
100
|
-
return fs.createReadStream(join(tmpPath, name, "db", "dump.txt"))
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
77
|
/**
|
|
105
78
|
* Used to retrieve a handlebars file from the system which will be used as a template.
|
|
106
79
|
* This is allowable as the template handlebars files should be static and identical across
|
|
@@ -124,98 +97,8 @@ exports.apiFileReturn = contents => {
|
|
|
124
97
|
return fs.createReadStream(path)
|
|
125
98
|
}
|
|
126
99
|
|
|
127
|
-
exports.
|
|
128
|
-
|
|
129
|
-
if (excludeRows) {
|
|
130
|
-
ids.push(TABLE_ROW_PREFIX)
|
|
131
|
-
}
|
|
132
|
-
return doc =>
|
|
133
|
-
!ids.map(key => doc._id.includes(key)).reduce((prev, curr) => prev || curr)
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Local utility to back up the database state for an app, excluding global user
|
|
138
|
-
* data or user relationships.
|
|
139
|
-
* @param {string} appId The app to backup
|
|
140
|
-
* @param {object} config Config to send to export DB
|
|
141
|
-
* @param {boolean} excludeRows Flag to state whether the export should include data.
|
|
142
|
-
* @returns {*} either a string or a stream of the backup
|
|
143
|
-
*/
|
|
144
|
-
const backupAppData = async (appId, config, excludeRows) => {
|
|
145
|
-
return await exports.exportDB(appId, {
|
|
146
|
-
...config,
|
|
147
|
-
filter: exports.defineFilter(excludeRows),
|
|
148
|
-
})
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Takes a copy of the database state for an app to the object store.
|
|
153
|
-
* @param {string} appId The ID of the app which is to be backed up.
|
|
154
|
-
* @param {string} backupName The name of the backup located in the object store.
|
|
155
|
-
* @return {*} a readable stream to the completed backup file
|
|
156
|
-
*/
|
|
157
|
-
exports.performBackup = async (appId, backupName) => {
|
|
158
|
-
return await backupAppData(appId, { exportName: backupName })
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Streams a backup of the database state for an app
|
|
163
|
-
* @param {string} appId The ID of the app which is to be backed up.
|
|
164
|
-
* @param {boolean} excludeRows Flag to state whether the export should include data.
|
|
165
|
-
* @returns {*} a readable stream of the backup which is written in real time
|
|
166
|
-
*/
|
|
167
|
-
exports.streamBackup = async (appId, excludeRows) => {
|
|
168
|
-
return await backupAppData(appId, { stream: true }, excludeRows)
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Exports a DB to either file or a variable (memory).
|
|
173
|
-
* @param {string} dbName the DB which is to be exported.
|
|
174
|
-
* @param {string} exportName optional - provide a filename to write the backup to a file
|
|
175
|
-
* @param {boolean} stream optional - whether to perform a full backup
|
|
176
|
-
* @param {function} filter optional - a filter function to clear out any un-wanted docs.
|
|
177
|
-
* @return {*} either a readable stream or a string
|
|
178
|
-
*/
|
|
179
|
-
exports.exportDB = async (dbName, { stream, filter, exportName } = {}) => {
|
|
180
|
-
// streaming a DB dump is a bit more complicated, can't close DB
|
|
181
|
-
if (stream) {
|
|
182
|
-
const db = dangerousGetDB(dbName)
|
|
183
|
-
const memStream = new MemoryStream()
|
|
184
|
-
memStream.on("end", async () => {
|
|
185
|
-
await closeDB(db)
|
|
186
|
-
})
|
|
187
|
-
db.dump(memStream, { filter })
|
|
188
|
-
return memStream
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
return doWithDB(dbName, async db => {
|
|
192
|
-
// Write the dump to file if required
|
|
193
|
-
if (exportName) {
|
|
194
|
-
const path = join(budibaseTempDir(), exportName)
|
|
195
|
-
const writeStream = fs.createWriteStream(path)
|
|
196
|
-
await db.dump(writeStream, { filter })
|
|
197
|
-
|
|
198
|
-
// Upload the dump to the object store if self hosted
|
|
199
|
-
if (env.SELF_HOSTED) {
|
|
200
|
-
await streamUpload(
|
|
201
|
-
ObjectStoreBuckets.BACKUPS,
|
|
202
|
-
join(dbName, exportName),
|
|
203
|
-
fs.createReadStream(path)
|
|
204
|
-
)
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
return fs.createReadStream(path)
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
// Stringify the dump in memory if required
|
|
211
|
-
const memStream = new MemoryStream()
|
|
212
|
-
let appString = ""
|
|
213
|
-
memStream.on("data", chunk => {
|
|
214
|
-
appString += chunk.toString()
|
|
215
|
-
})
|
|
216
|
-
await db.dump(memStream, { filter })
|
|
217
|
-
return appString
|
|
218
|
-
})
|
|
100
|
+
exports.streamFile = path => {
|
|
101
|
+
return fs.createReadStream(path)
|
|
219
102
|
}
|
|
220
103
|
|
|
221
104
|
/**
|
|
@@ -6,6 +6,7 @@ const {
|
|
|
6
6
|
streamUpload,
|
|
7
7
|
retrieve,
|
|
8
8
|
retrieveToTmp,
|
|
9
|
+
retrieveDirectory,
|
|
9
10
|
deleteFolder,
|
|
10
11
|
uploadDirectory,
|
|
11
12
|
downloadTarball,
|
|
@@ -27,6 +28,7 @@ exports.upload = upload
|
|
|
27
28
|
exports.streamUpload = streamUpload
|
|
28
29
|
exports.retrieve = retrieve
|
|
29
30
|
exports.retrieveToTmp = retrieveToTmp
|
|
31
|
+
exports.retrieveDirectory = retrieveDirectory
|
|
30
32
|
exports.deleteFolder = deleteFolder
|
|
31
33
|
exports.uploadDirectory = uploadDirectory
|
|
32
34
|
exports.downloadTarball = downloadTarball
|
|
@@ -2,6 +2,7 @@ const { getRowParams, USER_METDATA_PREFIX } = require("../../db/utils")
|
|
|
2
2
|
const {
|
|
3
3
|
isDevAppID,
|
|
4
4
|
getDevelopmentAppID,
|
|
5
|
+
getProdAppID,
|
|
5
6
|
doWithDB,
|
|
6
7
|
} = require("@budibase/backend-core/db")
|
|
7
8
|
|
|
@@ -52,7 +53,8 @@ const getAppRows = async appId => {
|
|
|
52
53
|
* Rows duplicates may exist across apps due to data import so they are not filtered out.
|
|
53
54
|
*/
|
|
54
55
|
exports.getUniqueRows = async appIds => {
|
|
55
|
-
let uniqueRows = []
|
|
56
|
+
let uniqueRows = [],
|
|
57
|
+
rowsByApp = {}
|
|
56
58
|
const pairs = getAppPairs(appIds)
|
|
57
59
|
|
|
58
60
|
for (let pair of Object.values(pairs)) {
|
|
@@ -73,8 +75,10 @@ exports.getUniqueRows = async appIds => {
|
|
|
73
75
|
// this can't be done on all rows because app import results in
|
|
74
76
|
// duplicate row ids across apps
|
|
75
77
|
// the array pre-concat is important to avoid stack overflow
|
|
76
|
-
|
|
78
|
+
const prodId = getProdAppID(pair.devId || pair.prodId)
|
|
79
|
+
rowsByApp[prodId] = [...new Set(appRows)]
|
|
80
|
+
uniqueRows = uniqueRows.concat(rowsByApp[prodId])
|
|
77
81
|
}
|
|
78
82
|
|
|
79
|
-
return uniqueRows
|
|
83
|
+
return { rows: uniqueRows, appRows: rowsByApp }
|
|
80
84
|
}
|