diff --git a/packages/builder/src/App.svelte b/packages/builder/src/App.svelte
index 18742fa84c..de64d43249 100644
--- a/packages/builder/src/App.svelte
+++ b/packages/builder/src/App.svelte
@@ -17,14 +17,6 @@
}
onMount(async () => {
- const res = await fetch(`/api/client/id`)
- const json = await res.json()
-
- store.update(state => {
- state.clientId = json
- return state
- })
-
window.addEventListener("error", showErrorBanner)
window.addEventListener("unhandledrejection", showErrorBanner)
})
@@ -34,8 +26,7 @@
-{#if $store.clientId}
-
-
-
-{/if}
+
+
+
+
diff --git a/packages/builder/src/builderStore/loadComponentLibraries.js b/packages/builder/src/builderStore/loadComponentLibraries.js
index 522d46fbe9..ada00134f4 100644
--- a/packages/builder/src/builderStore/loadComponentLibraries.js
+++ b/packages/builder/src/builderStore/loadComponentLibraries.js
@@ -1,11 +1,10 @@
/**
* Fetches the definitions for component library components. This includes
* their props and other metadata from components.json.
- * @param {string} clientId - ID of the current client
* @param {string} appId - ID of the currently running app
*/
-export const fetchComponentLibDefinitions = async (clientId, appId) => {
- const LIB_DEFINITION_URL = `/${clientId}/${appId}/components/definitions`
+export const fetchComponentLibDefinitions = async appId => {
+ const LIB_DEFINITION_URL = `/${appId}/components/definitions`
try {
const libDefinitionResponse = await fetch(LIB_DEFINITION_URL)
return await libDefinitionResponse.json()
diff --git a/packages/builder/src/builderStore/store/index.js b/packages/builder/src/builderStore/store/index.js
index 7a7ee38b78..5adb1b88f3 100644
--- a/packages/builder/src/builderStore/store/index.js
+++ b/packages/builder/src/builderStore/store/index.js
@@ -94,10 +94,7 @@ const setPackage = (store, initial) => async pkg => {
}
initial.libraries = await fetchComponentLibModules(pkg.application)
- initial.components = await fetchComponentLibDefinitions(
- pkg.clientId,
- pkg.application._id
- )
+ initial.components = await fetchComponentLibDefinitions(pkg.application._id)
initial.appname = pkg.application.name
initial.appId = pkg.application._id
initial.pages = pkg.pages
diff --git a/packages/builder/src/pages/[application]/_layout.svelte b/packages/builder/src/pages/[application]/_layout.svelte
index 8149171878..df3b05a4c6 100644
--- a/packages/builder/src/pages/[application]/_layout.svelte
+++ b/packages/builder/src/pages/[application]/_layout.svelte
@@ -13,7 +13,7 @@
let promise = getPackage()
async function getPackage() {
- const res = await fetch(`/api/${$store.clientId}/${application}/appPackage`)
+ const res = await fetch(`/api/${application}/appPackage`)
const pkg = await res.json()
if (res.ok) {
diff --git a/packages/cli/src/commands/init/initHandler.js b/packages/cli/src/commands/init/initHandler.js
index 27b68e48c5..0467633ee8 100644
--- a/packages/cli/src/commands/init/initHandler.js
+++ b/packages/cli/src/commands/init/initHandler.js
@@ -13,6 +13,7 @@ module.exports = opts => {
const run = async opts => {
try {
await ensureAppDir(opts)
+ await setEnvironmentVariables(opts)
await prompts(opts)
await createClientDatabase(opts)
await createDevEnvFile(opts)
@@ -22,18 +23,22 @@ const run = async opts => {
}
}
-const ensureAppDir = async opts => {
- opts.dir = xPlatHomeDir(opts.dir)
- await ensureDir(opts.dir)
-
+const setEnvironmentVariables = async opts => {
if (opts.database === "local") {
const dataDir = join(opts.dir, ".data")
await ensureDir(dataDir)
process.env.COUCH_DB_URL =
dataDir + (dataDir.endsWith("/") || dataDir.endsWith("\\") ? "" : "/")
+ } else {
+ process.env.COUCH_DB_URL = opts.couchDbUrl
}
}
+const ensureAppDir = async opts => {
+ opts.dir = xPlatHomeDir(opts.dir)
+ await ensureDir(opts.dir)
+}
+
const prompts = async opts => {
const questions = [
{
@@ -54,6 +59,10 @@ const prompts = async opts => {
}
const createClientDatabase = async opts => {
+ // cannot be a top level require as it
+ // will cause environment module to be loaded prematurely
+ const clientDb = require("@budibase/server/src/db/clientDb")
+
if (opts.clientId === "new") {
// cannot be a top level require as it
// will cause environment module to be loaded prematurely
@@ -65,13 +74,10 @@ const createClientDatabase = async opts => {
while (isExisting) {
i += 1
opts.clientId = i.toString()
- isExisting = existing.includes(`client-${opts.clientId}`)
+ isExisting = existing.includes(clientDb.name(opts.clientId))
}
}
- // cannot be a top level require as it
- // will cause environment module to be loaded prematurely
- const clientDb = require("@budibase/server/src/db/clientDb")
await clientDb.create(opts.clientId)
}
diff --git a/packages/cli/src/commands/new/newHandler.js b/packages/cli/src/commands/new/newHandler.js
index b533266d0e..e020c5f9da 100644
--- a/packages/cli/src/commands/new/newHandler.js
+++ b/packages/cli/src/commands/new/newHandler.js
@@ -19,7 +19,9 @@ const run = async opts => {
exec(`cd ${join(opts.dir, opts.applicationId)} && npm install`)
console.log(chalk.green(`Budibase app ${opts.name} created!`))
} catch (error) {
- console.error(chalk.red("Error creating new app", error))
+ console.error(
+ chalk.red("Error creating new app", JSON.stringify(error, { space: 2 }))
+ )
}
}
diff --git a/packages/server/.vscode/launch.json b/packages/server/.vscode/launch.json
index 92bf424e35..964e9297f4 100644
--- a/packages/server/.vscode/launch.json
+++ b/packages/server/.vscode/launch.json
@@ -8,7 +8,7 @@
"type": "node",
"request": "launch",
"name": "Start Server",
- "program": "${workspaceFolder}/src/index.js"
+ "program": "${workspaceFolder}/../cli/bin/budi"
},
{
"type": "node",
@@ -88,6 +88,19 @@
"program": "${workspaceFolder}/node_modules/jest-cli/bin/jest",
}
},
+ {
+ "type": "node",
+ "request": "launch",
+ "name": "Jest - Applications",
+ "program": "${workspaceFolder}/node_modules/.bin/jest",
+ "args": ["application.spec", "--runInBand"],
+ "console": "integratedTerminal",
+ "internalConsoleOptions": "neverOpen",
+ "disableOptimisticBPs": true,
+ "windows": {
+ "program": "${workspaceFolder}/node_modules/jest-cli/bin/jest",
+ }
+ },
{
"type": "node",
"request": "launch",
diff --git a/packages/server/src/api/controllers/application.js b/packages/server/src/api/controllers/application.js
index b50ab78f66..8160e4a5bf 100644
--- a/packages/server/src/api/controllers/application.js
+++ b/packages/server/src/api/controllers/application.js
@@ -1,11 +1,12 @@
const CouchDB = require("../../db")
+const ClientDb = require("../../db/clientDb")
const { getPackageForBuilder } = require("../../utilities/builder")
const uuid = require("uuid")
const env = require("../../environment")
exports.fetch = async function(ctx) {
- const clientDb = new CouchDB(`client-${env.CLIENT_ID}`)
- const body = await clientDb.query("client/by_type", {
+ const db = new CouchDB(ClientDb.name(env.CLIENT_ID))
+ const body = await db.query("client/by_type", {
include_docs: true,
key: ["app"],
})
@@ -14,13 +15,13 @@ exports.fetch = async function(ctx) {
}
exports.fetchAppPackage = async function(ctx) {
- const clientDb = new CouchDB(`client-${env.CLIENT_ID}`)
- const application = await clientDb.get(ctx.params.applicationId)
+ const db = new CouchDB(ClientDb.name(env.CLIENT_ID))
+ const application = await db.get(ctx.params.applicationId)
ctx.body = await getPackageForBuilder(ctx.config, application)
}
exports.create = async function(ctx) {
- const clientDb = new CouchDB(`client-${env.CLIENT_ID}`)
+ const db = new CouchDB(ClientDb.name(env.CLIENT_ID))
const newApplication = {
_id: uuid.v4().replace(/-/g, ""),
@@ -34,7 +35,7 @@ exports.create = async function(ctx) {
...ctx.request.body,
}
- const { rev } = await clientDb.post(newApplication)
+ const { rev } = await db.post(newApplication)
newApplication._rev = rev
ctx.body = newApplication
ctx.message = `Application ${ctx.request.body.name} created successfully`
diff --git a/packages/server/src/api/controllers/auth.js b/packages/server/src/api/controllers/auth.js
index c55ccabe5b..4cfc2f438a 100644
--- a/packages/server/src/api/controllers/auth.js
+++ b/packages/server/src/api/controllers/auth.js
@@ -1,5 +1,6 @@
const jwt = require("jsonwebtoken")
const CouchDB = require("../../db")
+const ClientDb = require("../../db/clientDb")
const bcrypt = require("../../utilities/bcrypt")
const env = require("../../environment")
@@ -14,7 +15,7 @@ exports.authenticate = async ctx => {
const appId = referer[3]
// find the instance that the user is associated with
- const db = new CouchDB(`client-${env.CLIENT_ID}`)
+ const db = new CouchDB(ClientDb.name(env.CLIENT_ID))
const app = await db.get(appId)
const instanceId = app.userInstanceMap[username]
diff --git a/packages/server/src/api/controllers/component.js b/packages/server/src/api/controllers/component.js
index 3523ed3f28..0b07826555 100644
--- a/packages/server/src/api/controllers/component.js
+++ b/packages/server/src/api/controllers/component.js
@@ -1,12 +1,14 @@
const CouchDB = require("../../db")
+const ClientDb = require("../../db/clientDb")
const { resolve, join } = require("path")
const {
budibaseTempDir,
budibaseAppsDir,
} = require("../../utilities/budibaseDir")
+const env = require("../../environment")
exports.fetchAppComponentDefinitions = async function(ctx) {
- const db = new CouchDB(`client-${ctx.params.clientId}`)
+ const db = new CouchDB(ClientDb.name(env.CLIENT_ID))
const app = await db.get(ctx.params.appId)
const componentDefinitions = app.componentLibraries.reduce(
diff --git a/packages/server/src/api/controllers/instance.js b/packages/server/src/api/controllers/instance.js
index a759777187..19edf53293 100644
--- a/packages/server/src/api/controllers/instance.js
+++ b/packages/server/src/api/controllers/instance.js
@@ -1,13 +1,12 @@
const CouchDB = require("../../db")
+const client = require("../../db/clientDb")
const uuid = require("uuid")
const env = require("../../environment")
-const clientDatabaseId = clientId => `client-${clientId}`
-
exports.create = async function(ctx) {
const instanceName = ctx.request.body.name
const uid = uuid.v4().replace(/-/g, "")
- const instanceId = `${ctx.params.applicationId.substring(0,7)}_${uid}`
+ const instanceId = `inst_${ctx.params.applicationId.substring(0,7)}_${uid}`
const { applicationId } = ctx.params
const clientId = env.CLIENT_ID
const db = new CouchDB(instanceId)
@@ -34,7 +33,7 @@ exports.create = async function(ctx) {
})
// Add the new instance under the app clientDB
- const clientDb = new CouchDB(clientDatabaseId(clientId))
+ const clientDb = new CouchDB(client.name(clientId))
const budibaseApp = await clientDb.get(applicationId)
const instance = { _id: instanceId, name: instanceName }
budibaseApp.instances.push(instance)
@@ -52,7 +51,7 @@ exports.destroy = async function(ctx) {
// remove instance from client application document
const { metadata } = designDoc
- const clientDb = new CouchDB(clientDatabaseId(metadata.clientId))
+ const clientDb = new CouchDB(client.name(metadata.clientId))
const budibaseApp = await clientDb.get(metadata.applicationId)
budibaseApp.instances = budibaseApp.instances.filter(
instance => instance !== ctx.params.instanceId
diff --git a/packages/server/src/api/controllers/static.js b/packages/server/src/api/controllers/static.js
index 3badf1940a..aeaa4319f8 100644
--- a/packages/server/src/api/controllers/static.js
+++ b/packages/server/src/api/controllers/static.js
@@ -4,10 +4,11 @@ const {
budibaseAppsDir,
budibaseTempDir,
} = require("../../utilities/budibaseDir")
+const env = require("../../environment")
exports.serveBuilder = async function(ctx) {
let builderPath = resolve(process.cwd(), "builder")
-
+ ctx.cookies.set("builder:token", env.ADMIN_SECRET)
await send(ctx, ctx.file, { root: ctx.devPath || builderPath })
}
diff --git a/packages/server/src/api/controllers/user.js b/packages/server/src/api/controllers/user.js
index a42e3dcf93..2be0132a47 100644
--- a/packages/server/src/api/controllers/user.js
+++ b/packages/server/src/api/controllers/user.js
@@ -1,4 +1,5 @@
const CouchDB = require("../../db")
+const clientDb = require("../../db/clientDb")
const bcrypt = require("../../utilities/bcrypt")
const env = require("../../environment")
@@ -30,14 +31,14 @@ exports.create = async function(ctx) {
})
// the clientDB needs to store a map of users against the app
- const clientDb = new CouchDB(`client-${env.CLIENT_ID}`)
- const app = await clientDb.get(appId)
+ const db = new CouchDB(clientDb.name(env.CLIENT_ID))
+ const app = await db.get(appId)
app.userInstanceMap = {
...app.userInstanceMap,
[username]: ctx.params.instanceId,
}
- await clientDb.put(app)
+ await db.put(app)
ctx.status = 200
ctx.message = "User created successfully."
diff --git a/packages/server/src/api/routes/component.js b/packages/server/src/api/routes/component.js
index 3a5c7224c8..5df34381fa 100644
--- a/packages/server/src/api/routes/component.js
+++ b/packages/server/src/api/routes/component.js
@@ -4,7 +4,7 @@ const controller = require("../controllers/component")
const router = Router()
router.get(
- "/:clientId/:appId/components/definitions",
+ "/:appId/components/definitions",
controller.fetchAppComponentDefinitions
)
diff --git a/packages/server/src/api/routes/static.js b/packages/server/src/api/routes/static.js
index 606173b8fe..5909d31d09 100644
--- a/packages/server/src/api/routes/static.js
+++ b/packages/server/src/api/routes/static.js
@@ -1,21 +1,26 @@
const Router = require("@koa/router")
const controller = require("../controllers/static")
const { budibaseTempDir } = require("../../utilities/budibaseDir")
+const env = require("../../environment")
const router = Router()
+router.param("file", async (file, ctx, next) => {
+ ctx.file = file && file.includes(".") ? file : "index.html"
+
+ // Serving the client library from your local dir in dev
+ if (ctx.isDev && ctx.file.startsWith("budibase-client")) {
+ ctx.devPath = budibaseTempDir()
+ }
+
+ await next()
+})
+
+if (env.NODE_ENV !== "production") {
+ router.get("/_builder/:file*", controller.serveBuilder)
+}
+
router
- .param("file", async (file, ctx, next) => {
- ctx.file = file && file.includes(".") ? file : "index.html"
-
- // Serving the client library from your local dir in dev
- if (ctx.isDev && ctx.file.startsWith("budibase-client")) {
- ctx.devPath = budibaseTempDir()
- }
-
- await next()
- })
- .get("/_builder/:file*", controller.serveBuilder)
.get("/:appId/componentlibrary", controller.serveComponentLibrary)
.get("/:appId/:file*", controller.serveApp)
diff --git a/packages/server/src/api/routes/tests/application.spec.js b/packages/server/src/api/routes/tests/application.spec.js
index fa8c9d712e..3619b59477 100644
--- a/packages/server/src/api/routes/tests/application.spec.js
+++ b/packages/server/src/api/routes/tests/application.spec.js
@@ -1,6 +1,9 @@
const {
createClientDatabase,
- supertest
+ createApplication,
+ destroyClientDatabase,
+ supertest,
+ defaultHeaders
} = require("./couchTestUtils")
describe("/applications", () => {
@@ -9,26 +12,47 @@ describe("/applications", () => {
beforeAll(async () => {
({ request, server } = await supertest())
- await createClientDatabase(request)
});
+ beforeEach(async () => {
+ await createClientDatabase(request)
+ })
+
+ afterEach(async () => {
+ await destroyClientDatabase(request)
+ })
+
afterAll(async () => {
server.close()
})
describe("create", () => {
- it("returns a success message when the application is successfully created", done => {
- request
+ it("returns a success message when the application is successfully created", async () => {
+ const res = await request
.post("/api/applications")
.send({ name: "My App" })
- .set("Accept", "application/json")
+ .set(defaultHeaders)
.expect('Content-Type', /json/)
.expect(200)
- .end((err, res) => {
- expect(res.res.statusMessage).toEqual("Application My App created successfully")
- expect(res.body._id).toBeDefined()
- done();
- });
- })
- });
-});
+ expect(res.res.statusMessage).toEqual("Application My App created successfully")
+ expect(res.body._id).toBeDefined()
+ })
+ })
+
+ describe("fetch", () => {
+ it("lists all applications", async () => {
+
+ await createApplication(request, "app1")
+ await createApplication(request, "app2")
+
+ const res = await request
+ .get("/api/applications")
+ .set(defaultHeaders)
+ .expect('Content-Type', /json/)
+ .expect(200)
+
+ expect(res.body.length).toBe(2)
+ })
+ })
+
+})
diff --git a/packages/server/src/db/client.js b/packages/server/src/db/client.js
index cb2867cd47..f2c090b564 100644
--- a/packages/server/src/db/client.js
+++ b/packages/server/src/db/client.js
@@ -3,7 +3,7 @@ const allDbs = require("pouchdb-all-dbs")
const { budibaseAppsDir } = require("../utilities/budibaseDir")
const env = require("../environment")
-const COUCH_DB_URL = env.COUCH_DB_URL || `leveldb://${budibaseAppsDir()}/`
+const COUCH_DB_URL = env.COUCH_DB_URL || `leveldb://${budibaseAppsDir().replace(/\\/g, "/")}/.data/`
const isInMemory = env.NODE_ENV === "jest"
if (isInMemory) PouchDB.plugin(require("pouchdb-adapter-memory"))
diff --git a/packages/server/src/db/clientDb.js b/packages/server/src/db/clientDb.js
index 1dace2c652..b85cd43110 100644
--- a/packages/server/src/db/clientDb.js
+++ b/packages/server/src/db/clientDb.js
@@ -1,7 +1,7 @@
const CouchDB = require("./client")
exports.create = async clientId => {
- const dbId = `client-${clientId}`
+ const dbId = exports.name(clientId)
const db = new CouchDB(dbId)
await db.put({
_id: "_design/client",
@@ -17,6 +17,10 @@ exports.create = async clientId => {
}
exports.destroy = async function(clientId) {
- const dbId = `client-${clientId}`
+ const dbId = exports.name(clientId)
await new CouchDB(dbId).destroy()
}
+
+exports.name = function(clientId) {
+ return `client_${clientId}`
+}
diff --git a/packages/server/src/middleware/authenticated.js b/packages/server/src/middleware/authenticated.js
index 3dfeec4d35..43c8f013e1 100644
--- a/packages/server/src/middleware/authenticated.js
+++ b/packages/server/src/middleware/authenticated.js
@@ -15,6 +15,12 @@ module.exports = async (ctx, next) => {
return
}
+ if (ctx.isDev && ctx.cookies.get("builder:token") === env.ADMIN_SECRET) {
+ ctx.isAuthenticated = true
+ await next()
+ return
+ }
+
const token = ctx.cookies.get("budibase:token")
if (!token) {