mirror of https://github.com/Budibase/budibase.git
committed by
GitHub
30 changed files with 2159 additions and 92 deletions
@ -0,0 +1,50 @@ |
|||
<script> |
|||
import { notifications, ModalContent, Dropzone, Body } from "@budibase/bbui" |
|||
import { post } from "builderStore/api" |
|||
|
|||
let submitting = false |
|||
|
|||
$: value = { file: null } |
|||
|
|||
async function importApps() { |
|||
submitting = true |
|||
|
|||
try { |
|||
// Create form data to create app |
|||
let data = new FormData() |
|||
data.append("importFile", value.file) |
|||
|
|||
// Create App |
|||
const importResp = await post("/api/cloud/import", data, {}) |
|||
const importJson = await importResp.json() |
|||
if (!importResp.ok) { |
|||
throw new Error(importJson.message) |
|||
} |
|||
// now reload to get to login |
|||
window.location.reload() |
|||
} catch (error) { |
|||
notifications.error(error) |
|||
submitting = false |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<ModalContent |
|||
title="Import apps" |
|||
confirmText="Import apps" |
|||
onConfirm={importApps} |
|||
disabled={!value.file} |
|||
> |
|||
<Body |
|||
>Please upload the file that was exported from your Cloud environment to get |
|||
started</Body |
|||
> |
|||
<Dropzone |
|||
gallery={false} |
|||
label="File to import" |
|||
value={[value.file]} |
|||
on:change={e => { |
|||
value.file = e.detail?.[0] |
|||
}} |
|||
/> |
|||
</ModalContent> |
|||
File diff suppressed because it is too large
@ -0,0 +1,92 @@ |
|||
const env = require("../../environment") |
|||
const { getAllApps } = require("@budibase/auth/db") |
|||
const CouchDB = require("../../db") |
|||
const { |
|||
exportDB, |
|||
sendTempFile, |
|||
readFileSync, |
|||
} = require("../../utilities/fileSystem") |
|||
const { stringToReadStream } = require("../../utilities") |
|||
const { getGlobalDBName, getGlobalDB } = require("@budibase/auth/tenancy") |
|||
const { create } = require("./application") |
|||
const { getDocParams, DocumentTypes, isDevAppID } = require("../../db/utils") |
|||
|
|||
async function createApp(appName, appImport) { |
|||
const ctx = { |
|||
request: { |
|||
body: { |
|||
templateString: appImport, |
|||
name: appName, |
|||
}, |
|||
}, |
|||
} |
|||
return create(ctx) |
|||
} |
|||
|
|||
exports.exportApps = async ctx => { |
|||
if (env.SELF_HOSTED || !env.MULTI_TENANCY) { |
|||
ctx.throw(400, "Exporting only allowed in multi-tenant cloud environments.") |
|||
} |
|||
const apps = await getAllApps(CouchDB, { all: true }) |
|||
const globalDBString = await exportDB(getGlobalDBName()) |
|||
let allDBs = { |
|||
global: globalDBString, |
|||
} |
|||
for (let app of apps) { |
|||
// only export the dev apps as they will be the latest, the user can republish the apps
|
|||
// in their self hosted environment
|
|||
if (isDevAppID(app._id)) { |
|||
allDBs[app.name] = await exportDB(app._id) |
|||
} |
|||
} |
|||
const filename = `cloud-export-${new Date().getTime()}.txt` |
|||
ctx.attachment(filename) |
|||
ctx.body = sendTempFile(JSON.stringify(allDBs)) |
|||
} |
|||
|
|||
async function getAllDocType(db, docType) { |
|||
const response = await db.allDocs( |
|||
getDocParams(docType, null, { |
|||
include_docs: true, |
|||
}) |
|||
) |
|||
return response.rows.map(row => row.doc) |
|||
} |
|||
|
|||
exports.importApps = async ctx => { |
|||
if (!env.SELF_HOSTED || env.MULTI_TENANCY) { |
|||
ctx.throw(400, "Importing only allowed in self hosted environments.") |
|||
} |
|||
const apps = await getAllApps(CouchDB, { all: true }) |
|||
if ( |
|||
apps.length !== 0 || |
|||
!ctx.request.files || |
|||
!ctx.request.files.importFile |
|||
) { |
|||
ctx.throw( |
|||
400, |
|||
"Import file is required and environment must be fresh to import apps." |
|||
) |
|||
} |
|||
const importFile = ctx.request.files.importFile |
|||
const importString = readFileSync(importFile.path) |
|||
const dbs = JSON.parse(importString) |
|||
const globalDbImport = dbs.global |
|||
// remove from the list of apps
|
|||
delete dbs.global |
|||
const globalDb = getGlobalDB() |
|||
// load the global db first
|
|||
await globalDb.load(stringToReadStream(globalDbImport)) |
|||
for (let [appName, appImport] of Object.entries(dbs)) { |
|||
await createApp(appName, appImport) |
|||
} |
|||
// once apps are created clean up the global db
|
|||
let users = await getAllDocType(globalDb, DocumentTypes.USER) |
|||
for (let user of users) { |
|||
delete user.tenantId |
|||
} |
|||
await globalDb.bulkDocs(users) |
|||
ctx.body = { |
|||
message: "Apps successfully imported.", |
|||
} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
const Router = require("@koa/router") |
|||
const controller = require("../controllers/cloud") |
|||
const authorized = require("../../middleware/authorized") |
|||
const { BUILDER } = require("@budibase/auth/permissions") |
|||
|
|||
const router = Router() |
|||
|
|||
router |
|||
.get("/api/cloud/export", authorized(BUILDER), controller.exportApps) |
|||
// has to be public, only run if apps don't exist
|
|||
.post("/api/cloud/import", controller.importApps) |
|||
|
|||
module.exports = router |
|||
File diff suppressed because it is too large
Loading…
Reference in new issue