Merge pull request #10900 from Budibase/budi-7010/export_controller_as_post
BUDI-7010 - Export controller as post
This commit is contained in:
commit
672804c150
|
@ -1,5 +1,11 @@
|
|||
<script>
|
||||
import { ModalContent, Toggle, Body, InlineAlert } from "@budibase/bbui"
|
||||
import {
|
||||
ModalContent,
|
||||
Toggle,
|
||||
Body,
|
||||
InlineAlert,
|
||||
notifications,
|
||||
} from "@budibase/bbui"
|
||||
|
||||
export let app
|
||||
export let published
|
||||
|
@ -8,10 +14,45 @@
|
|||
$: title = published ? "Export published app" : "Export latest app"
|
||||
$: confirmText = published ? "Export published" : "Export latest"
|
||||
|
||||
const exportApp = () => {
|
||||
const exportApp = async () => {
|
||||
const id = published ? app.prodId : app.devId
|
||||
const appName = encodeURIComponent(app.name)
|
||||
window.location = `/api/backups/export?appId=${id}&appname=${appName}&excludeRows=${excludeRows}`
|
||||
const url = `/api/backups/export?appId=${id}`
|
||||
await downloadFile(url, { excludeRows })
|
||||
}
|
||||
|
||||
async function downloadFile(url, body) {
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
})
|
||||
|
||||
if (response.ok) {
|
||||
const contentDisposition = response.headers.get("Content-Disposition")
|
||||
|
||||
const matches = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/.exec(
|
||||
contentDisposition
|
||||
)
|
||||
|
||||
const filename = matches[1].replace(/['"]/g, "")
|
||||
|
||||
const url = URL.createObjectURL(await response.blob())
|
||||
|
||||
const link = document.createElement("a")
|
||||
link.href = url
|
||||
link.download = filename
|
||||
link.click()
|
||||
|
||||
URL.revokeObjectURL(url)
|
||||
} else {
|
||||
notifications.error("Error exporting the app.")
|
||||
}
|
||||
} catch (error) {
|
||||
notifications.error(error.message || "Error downloading the exported app")
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,14 +1,22 @@
|
|||
import sdk from "../../sdk"
|
||||
import { events, context } from "@budibase/backend-core"
|
||||
import { events, context, db } from "@budibase/backend-core"
|
||||
import { DocumentType } from "../../db/utils"
|
||||
import { isQsTrue } from "../../utilities"
|
||||
import { Ctx } from "@budibase/types"
|
||||
|
||||
interface ExportAppDumpRequest {
|
||||
excludeRows: boolean
|
||||
}
|
||||
|
||||
export async function exportAppDump(ctx: Ctx<ExportAppDumpRequest>) {
|
||||
const { appId } = ctx.query as any
|
||||
const { excludeRows } = ctx.request.body
|
||||
|
||||
const [app] = await db.getAppsByIDs([appId])
|
||||
const appName = app.name
|
||||
|
||||
export async function exportAppDump(ctx: any) {
|
||||
let { appId, excludeRows } = ctx.query
|
||||
// remove the 120 second limit for the request
|
||||
ctx.req.setTimeout(0)
|
||||
const appName = decodeURI(ctx.query.appname)
|
||||
excludeRows = isQsTrue(excludeRows)
|
||||
|
||||
const backupIdentifier = `${appName}-export-${new Date().getTime()}.tar.gz`
|
||||
ctx.attachment(backupIdentifier)
|
||||
ctx.body = await sdk.backups.streamExportApp(appId, excludeRows)
|
||||
|
|
|
@ -5,7 +5,7 @@ import { permissions } from "@budibase/backend-core"
|
|||
|
||||
const router: Router = new Router()
|
||||
|
||||
router.get(
|
||||
router.post(
|
||||
"/api/backups/export",
|
||||
authorized(permissions.BUILDER),
|
||||
controller.exportAppDump
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import tk from "timekeeper"
|
||||
import * as setup from "./utilities"
|
||||
import { events } from "@budibase/backend-core"
|
||||
import sdk from "../../../sdk"
|
||||
import { checkBuilderEndpoint } from "./utilities/TestFunctions"
|
||||
import { mocks } from "@budibase/backend-core/tests"
|
||||
|
||||
describe("/backups", () => {
|
||||
let request = setup.getRequest()
|
||||
|
@ -16,7 +18,7 @@ describe("/backups", () => {
|
|||
describe("exportAppDump", () => {
|
||||
it("should be able to export app", async () => {
|
||||
const res = await request
|
||||
.get(`/api/backups/export?appId=${config.getAppId()}&appname=test`)
|
||||
.post(`/api/backups/export?appId=${config.getAppId()}`)
|
||||
.set(config.defaultHeaders())
|
||||
.expect(200)
|
||||
expect(res.headers["content-type"]).toEqual("application/gzip")
|
||||
|
@ -26,10 +28,24 @@ describe("/backups", () => {
|
|||
it("should apply authorization to endpoint", async () => {
|
||||
await checkBuilderEndpoint({
|
||||
config,
|
||||
method: "GET",
|
||||
method: "POST",
|
||||
url: `/api/backups/export?appId=${config.getAppId()}`,
|
||||
})
|
||||
})
|
||||
|
||||
it("should infer the app name from the app", async () => {
|
||||
tk.freeze(mocks.date.MOCK_DATE)
|
||||
|
||||
const res = await request
|
||||
.post(`/api/backups/export?appId=${config.getAppId()}`)
|
||||
.set(config.defaultHeaders())
|
||||
|
||||
expect(res.headers["content-disposition"]).toEqual(
|
||||
`attachment; filename="${
|
||||
config.getApp()!.name
|
||||
}-export-${mocks.date.MOCK_DATE.getTime()}.tar.gz"`
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("calculateBackupStats", () => {
|
||||
|
|
Loading…
Reference in New Issue