diff --git a/packages/server/src/api/controllers/assets.ts b/packages/server/src/api/controllers/assets.ts index 31e615a074..909c49751f 100644 --- a/packages/server/src/api/controllers/assets.ts +++ b/packages/server/src/api/controllers/assets.ts @@ -1,10 +1,12 @@ import { join } from "../../utilities/centralPath" -import { TOP_LEVEL_PATH } from "../../utilities/fileSystem" +import { TOP_LEVEL_PATH, DEV_ASSET_PATH } from "../../utilities/fileSystem" import { Ctx } from "@budibase/types" +import env from "../../environment" import send from "koa-send" // this is a public endpoint with no middlewares export const serveBuilderAssets = async function (ctx: Ctx) { - const builderPath = join(TOP_LEVEL_PATH, "builder") + let topLevelPath = env.isDev() ? DEV_ASSET_PATH : TOP_LEVEL_PATH + const builderPath = join(topLevelPath, "builder") await send(ctx, ctx.file, { root: builderPath }) } diff --git a/packages/server/src/api/index.ts b/packages/server/src/api/index.ts index 276bb7e209..9b10d64367 100644 --- a/packages/server/src/api/index.ts +++ b/packages/server/src/api/index.ts @@ -8,7 +8,7 @@ import { middleware as pro } from "@budibase/pro" import { apiEnabled, automationsEnabled } from "../features" import migrations from "../middleware/appMigrations" import { automationQueue } from "../automations" -import { serveBuilderAssets } from "./controllers/assets" +import assetRouter from "./routes/assets" export { shutdown } from "./routes/public" const compress = require("koa-compress") @@ -47,7 +47,8 @@ if (apiEnabled()) { .redirect("/", "/builder") // send assets before middleware - router.get("/builder/:file*", serveBuilderAssets) + router.use(assetRouter.routes()) + router.use(assetRouter.allowedMethods()) router .use( diff --git a/packages/server/src/api/routes/assets.ts b/packages/server/src/api/routes/assets.ts new file mode 100644 index 0000000000..c140408f0b --- /dev/null +++ b/packages/server/src/api/routes/assets.ts @@ -0,0 +1,11 @@ +import { addFileManagement } from "../utils" +import { serveBuilderAssets } from "../controllers/assets" +import Router from "@koa/router" + +const router: Router = new Router() + +addFileManagement(router) + +router.get("/builder/:file*", serveBuilderAssets) + +export default router diff --git a/packages/server/src/api/routes/static.ts b/packages/server/src/api/routes/static.ts index 8b921e7ba7..2fefba301e 100644 --- a/packages/server/src/api/routes/static.ts +++ b/packages/server/src/api/routes/static.ts @@ -1,32 +1,15 @@ import Router from "@koa/router" import * as controller from "../controllers/static" -import { budibaseTempDir } from "../../utilities/budibaseDir" import authorized from "../../middleware/authorized" import { permissions } from "@budibase/backend-core" -import env from "../../environment" +import { addFileManagement } from "../utils" import { paramResource } from "../../middleware/resourceId" -import { devClientLibPath } from "../../utilities/fileSystem" const { BUILDER, PermissionType, PermissionLevel } = permissions const router: Router = new Router() -/* istanbul ignore next */ -router.param("file", async (file: any, ctx: any, next: any) => { - ctx.file = file && file.includes(".") ? file : "index.html" - if (!ctx.file.startsWith("budibase-client")) { - return next() - } - // test serves from require - if (env.isTest()) { - const path = devClientLibPath() - ctx.devPath = path.split(ctx.file)[0] - } else if (env.isDev()) { - // Serving the client library from your local dir in dev - ctx.devPath = budibaseTempDir() - } - return next() -}) +addFileManagement(router) router .get("/api/assets/client", controller.serveClientLibrary) diff --git a/packages/server/src/api/routes/tests/assets.spec.ts b/packages/server/src/api/routes/tests/assets.spec.ts new file mode 100644 index 0000000000..df5587c7e6 --- /dev/null +++ b/packages/server/src/api/routes/tests/assets.spec.ts @@ -0,0 +1,29 @@ +import fs from "fs" +import { join } from "path" +import { DEV_ASSET_PATH } from "../../../utilities/fileSystem" +import * as setup from "./utilities" + +const path = join(DEV_ASSET_PATH, "builder", "index.html") +let addedIndexHtml = false +const config = setup.getConfig() + +beforeAll(async () => { + if (!fs.existsSync(path)) { + fs.writeFileSync(path, "", "utf8") + addedIndexHtml = true + } + await config.init() +}) + +afterAll(() => { + if (addedIndexHtml) { + fs.rmSync(path) + } +}) + +describe("/builder/:file*", () => { + it("should be able to retrieve the builder file", async () => { + const res = await config.api.assets.get("index.html") + expect(res.text).toContain(" { + ctx.file = file && file.includes(".") ? file : "index.html" + if (!ctx.file.startsWith("budibase-client")) { + return next() + } + // test serves from require + if (env.isTest()) { + const path = devClientLibPath() + ctx.devPath = path.split(ctx.file)[0] + } else if (env.isDev()) { + // Serving the client library from your local dir in dev + ctx.devPath = budibaseTempDir() + } + return next() + }) +} diff --git a/packages/server/src/tests/utilities/api/assets.ts b/packages/server/src/tests/utilities/api/assets.ts new file mode 100644 index 0000000000..6cb9f5dbe8 --- /dev/null +++ b/packages/server/src/tests/utilities/api/assets.ts @@ -0,0 +1,8 @@ +import { TestAPI } from "./base" + +export class AssetsAPI extends TestAPI { + get = async (path: string) => { + // has to be raw, body isn't JSON + return await this._requestRaw("get", `/builder/${path}`) + } +} diff --git a/packages/server/src/tests/utilities/api/index.ts b/packages/server/src/tests/utilities/api/index.ts index 8ed51cdc3a..ba99c2eca0 100644 --- a/packages/server/src/tests/utilities/api/index.ts +++ b/packages/server/src/tests/utilities/api/index.ts @@ -21,6 +21,7 @@ import { EnvironmentAPI } from "./environment" import { UserPublicAPI } from "./public/user" import { MiscAPI } from "./misc" import { OAuth2API } from "./oauth2" +import { AssetsAPI } from "./assets" export default class API { application: ApplicationAPI @@ -44,6 +45,7 @@ export default class API { user: UserAPI viewV2: ViewV2API webhook: WebhookAPI + assets: AssetsAPI public: { user: UserPublicAPI @@ -71,6 +73,7 @@ export default class API { this.user = new UserAPI(config) this.viewV2 = new ViewV2API(config) this.webhook = new WebhookAPI(config) + this.assets = new AssetsAPI(config) this.public = { user: new UserPublicAPI(config), } diff --git a/packages/server/src/utilities/fileSystem/filesystem.ts b/packages/server/src/utilities/fileSystem/filesystem.ts index b0a67ac94e..10feb3c404 100644 --- a/packages/server/src/utilities/fileSystem/filesystem.ts +++ b/packages/server/src/utilities/fileSystem/filesystem.ts @@ -8,6 +8,7 @@ import { v4 as uuid } from "uuid" export const TOP_LEVEL_PATH = env.TOP_LEVEL_PATH || resolve(join(__dirname, "..", "..", "..")) +export const DEV_ASSET_PATH = join(TOP_LEVEL_PATH, "packages", "server") /** * Upon first startup of instance there may not be everything we need in tmp directory, set it up.