{template.name}
diff --git a/packages/builder/src/pages/index.svelte b/packages/builder/src/pages/index.svelte
index fcf0f5af52..5706665190 100644
--- a/packages/builder/src/pages/index.svelte
+++ b/packages/builder/src/pages/index.svelte
@@ -46,12 +46,18 @@
modal.show()
}
+ function initiateAppImport() {
+ template = { fromFile: true }
+ modal.show()
+ }
+
checkIfKeysAndApps()
diff --git a/packages/server/src/api/controllers/application.js b/packages/server/src/api/controllers/application.js
index 91c79f1961..e899a2dca9 100644
--- a/packages/server/src/api/controllers/application.js
+++ b/packages/server/src/api/controllers/application.js
@@ -105,10 +105,16 @@ async function createInstance(template) {
// replicate the template data to the instance DB
if (template) {
- const templatePath = await downloadTemplate(...template.key.split("/"))
- const dbDumpReadStream = fs.createReadStream(
- join(templatePath, "db", "dump.txt")
- )
+ let dbDumpReadStream
+
+ if (template.fileImportPath) {
+ dbDumpReadStream = fs.createReadStream(template.fileImportPath)
+ } else {
+ const templatePath = await downloadTemplate(...template.key.split("/"))
+ dbDumpReadStream = fs.createReadStream(
+ join(templatePath, "db", "dump.txt")
+ )
+ }
const { ok } = await db.load(dbDumpReadStream)
if (!ok) {
throw "Error loading database dump from template."
diff --git a/packages/server/src/api/controllers/backup.js b/packages/server/src/api/controllers/backup.js
new file mode 100644
index 0000000000..9ba122ebb8
--- /dev/null
+++ b/packages/server/src/api/controllers/backup.js
@@ -0,0 +1,36 @@
+const { performDump } = require("../../utilities/templates")
+const path = require("path")
+const os = require("os")
+const fs = require("fs-extra")
+
+exports.exportAppDump = async function(ctx) {
+ const { appId } = ctx.request.body
+
+ const backupsDir = path.join(os.homedir(), ".budibase", "backups")
+ fs.ensureDirSync(backupsDir)
+
+ const backupIdentifier = `${appId} Backup: ${new Date()}.txt`
+
+ await performDump({
+ dir: backupsDir,
+ appId,
+ name: backupIdentifier,
+ })
+
+ ctx.status = 200
+ ctx.body = {
+ url: `/api/backups/download/${backupIdentifier}`,
+ }
+}
+
+exports.downloadAppDump = async function(ctx) {
+ const fileName = ctx.params.fileName
+
+ const backupsDir = path.join(os.homedir(), ".budibase", "backups")
+ fs.ensureDirSync(backupsDir)
+
+ const backupFile = path.join(backupsDir, fileName)
+
+ ctx.attachment(fileName)
+ ctx.body = fs.createReadStream(backupFile)
+}
diff --git a/packages/server/src/api/index.js b/packages/server/src/api/index.js
index c76eb82643..ea0ed4b875 100644
--- a/packages/server/src/api/index.js
+++ b/packages/server/src/api/index.js
@@ -5,6 +5,7 @@ const zlib = require("zlib")
const { budibaseAppsDir } = require("../utilities/budibaseDir")
const { isDev } = require("../utilities")
const { mainRoutes, authRoutes, staticRoutes } = require("./routes")
+const pkg = require("../../package.json")
const router = new Router()
const env = require("../environment")
@@ -32,6 +33,7 @@ router
await next()
})
.use("/health", ctx => (ctx.status = 200))
+ .use("/version", ctx => (ctx.body = pkg.version))
.use(authenticated)
// error handling middleware
diff --git a/packages/server/src/api/routes/backup.js b/packages/server/src/api/routes/backup.js
new file mode 100644
index 0000000000..d5136fb9e6
--- /dev/null
+++ b/packages/server/src/api/routes/backup.js
@@ -0,0 +1,16 @@
+const Router = require("@koa/router")
+const controller = require("../controllers/backup")
+const authorized = require("../../middleware/authorized")
+const { BUILDER } = require("../../utilities/security/permissions")
+
+const router = Router()
+
+router
+ .post("/api/backups/export", authorized(BUILDER), controller.exportAppDump)
+ .get(
+ "/api/backups/download/:fileName",
+ authorized(BUILDER),
+ controller.downloadAppDump
+ )
+
+module.exports = router
diff --git a/packages/server/src/api/routes/index.js b/packages/server/src/api/routes/index.js
index 68b0c3fc2b..002d2ec805 100644
--- a/packages/server/src/api/routes/index.js
+++ b/packages/server/src/api/routes/index.js
@@ -21,6 +21,7 @@ const permissionRoutes = require("./permission")
const datasourceRoutes = require("./datasource")
const queryRoutes = require("./query")
const hostingRoutes = require("./hosting")
+const backupRoutes = require("./backup")
exports.mainRoutes = [
deployRoutes,
@@ -42,6 +43,7 @@ exports.mainRoutes = [
datasourceRoutes,
queryRoutes,
hostingRoutes,
+ backupRoutes,
// these need to be handled last as they still use /api/:tableId
// this could be breaking as koa may recognise other routes as this
tableRoutes,
diff --git a/packages/server/src/utilities/templates.js b/packages/server/src/utilities/templates.js
index d5b5d5e257..fc38c51626 100644
--- a/packages/server/src/utilities/templates.js
+++ b/packages/server/src/utilities/templates.js
@@ -56,6 +56,19 @@ exports.downloadTemplate = async function(type, name) {
return dirName
}
+async function performDump({ dir, appId, name = "dump.txt" }) {
+ const writeStream = fs.createWriteStream(join(dir, name))
+ // perform couch dump
+ const instanceDb = new CouchDB(appId)
+ await instanceDb.dump(writeStream, {
+ filter: doc => {
+ return !doc._id.startsWith(DocumentTypes.USER)
+ },
+ })
+}
+
+exports.performDump = performDump
+
exports.exportTemplateFromApp = async function({ templateName, appId }) {
// Copy frontend files
const templatesDir = join(
@@ -67,13 +80,6 @@ exports.exportTemplateFromApp = async function({ templateName, appId }) {
"db"
)
fs.ensureDirSync(templatesDir)
- const writeStream = fs.createWriteStream(join(templatesDir, "dump.txt"))
- // perform couch dump
- const instanceDb = new CouchDB(appId)
- await instanceDb.dump(writeStream, {
- filter: doc => {
- return !doc._id.startsWith(DocumentTypes.USER)
- },
- })
+ await performDump({ dir: templatesDir, appId })
return templatesDir
}