diff --git a/packages/builder/src/components/start/ExportAppModal.svelte b/packages/builder/src/components/start/ExportAppModal.svelte index 948416b192..5cc3393a89 100644 --- a/packages/builder/src/components/start/ExportAppModal.svelte +++ b/packages/builder/src/components/start/ExportAppModal.svelte @@ -1,5 +1,11 @@ diff --git a/packages/server/src/api/controllers/backup.ts b/packages/server/src/api/controllers/backup.ts index 53e1bd1792..60312bd36c 100644 --- a/packages/server/src/api/controllers/backup.ts +++ b/packages/server/src/api/controllers/backup.ts @@ -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) { + 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) diff --git a/packages/server/src/api/routes/backup.ts b/packages/server/src/api/routes/backup.ts index fb455250a7..94e4cf957f 100644 --- a/packages/server/src/api/routes/backup.ts +++ b/packages/server/src/api/routes/backup.ts @@ -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 diff --git a/packages/server/src/api/routes/tests/backup.spec.ts b/packages/server/src/api/routes/tests/backup.spec.ts index ef362ef403..92e0176060 100644 --- a/packages/server/src/api/routes/tests/backup.spec.ts +++ b/packages/server/src/api/routes/tests/backup.spec.ts @@ -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", () => {