removing clientId from frontend, fixing invalid database name

This commit is contained in:
Michael Shanks 2020-05-18 06:40:29 +01:00
parent 42d19efeba
commit 1dc32a05e3
19 changed files with 128 additions and 76 deletions

View File

@ -17,14 +17,6 @@
} }
onMount(async () => { 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("error", showErrorBanner)
window.addEventListener("unhandledrejection", showErrorBanner) window.addEventListener("unhandledrejection", showErrorBanner)
}) })
@ -34,8 +26,7 @@
<AppNotification /> <AppNotification />
{#if $store.clientId} <Modal>
<Modal> <Router {routes} />
<Router {routes} /> </Modal>
</Modal>
{/if}

View File

@ -1,11 +1,10 @@
/** /**
* Fetches the definitions for component library components. This includes * Fetches the definitions for component library components. This includes
* their props and other metadata from components.json. * 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 * @param {string} appId - ID of the currently running app
*/ */
export const fetchComponentLibDefinitions = async (clientId, appId) => { export const fetchComponentLibDefinitions = async appId => {
const LIB_DEFINITION_URL = `/${clientId}/${appId}/components/definitions` const LIB_DEFINITION_URL = `/${appId}/components/definitions`
try { try {
const libDefinitionResponse = await fetch(LIB_DEFINITION_URL) const libDefinitionResponse = await fetch(LIB_DEFINITION_URL)
return await libDefinitionResponse.json() return await libDefinitionResponse.json()

View File

@ -94,10 +94,7 @@ const setPackage = (store, initial) => async pkg => {
} }
initial.libraries = await fetchComponentLibModules(pkg.application) initial.libraries = await fetchComponentLibModules(pkg.application)
initial.components = await fetchComponentLibDefinitions( initial.components = await fetchComponentLibDefinitions(pkg.application._id)
pkg.clientId,
pkg.application._id
)
initial.appname = pkg.application.name initial.appname = pkg.application.name
initial.appId = pkg.application._id initial.appId = pkg.application._id
initial.pages = pkg.pages initial.pages = pkg.pages

View File

@ -13,7 +13,7 @@
let promise = getPackage() let promise = getPackage()
async function 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() const pkg = await res.json()
if (res.ok) { if (res.ok) {

View File

@ -13,6 +13,7 @@ module.exports = opts => {
const run = async opts => { const run = async opts => {
try { try {
await ensureAppDir(opts) await ensureAppDir(opts)
await setEnvironmentVariables(opts)
await prompts(opts) await prompts(opts)
await createClientDatabase(opts) await createClientDatabase(opts)
await createDevEnvFile(opts) await createDevEnvFile(opts)
@ -22,18 +23,22 @@ const run = async opts => {
} }
} }
const ensureAppDir = async opts => { const setEnvironmentVariables = async opts => {
opts.dir = xPlatHomeDir(opts.dir)
await ensureDir(opts.dir)
if (opts.database === "local") { if (opts.database === "local") {
const dataDir = join(opts.dir, ".data") const dataDir = join(opts.dir, ".data")
await ensureDir(dataDir) await ensureDir(dataDir)
process.env.COUCH_DB_URL = process.env.COUCH_DB_URL =
dataDir + (dataDir.endsWith("/") || dataDir.endsWith("\\") ? "" : "/") 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 prompts = async opts => {
const questions = [ const questions = [
{ {
@ -54,6 +59,10 @@ const prompts = async opts => {
} }
const createClientDatabase = 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") { if (opts.clientId === "new") {
// cannot be a top level require as it // cannot be a top level require as it
// will cause environment module to be loaded prematurely // will cause environment module to be loaded prematurely
@ -65,13 +74,10 @@ const createClientDatabase = async opts => {
while (isExisting) { while (isExisting) {
i += 1 i += 1
opts.clientId = i.toString() 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) await clientDb.create(opts.clientId)
} }

View File

@ -19,7 +19,9 @@ const run = async opts => {
exec(`cd ${join(opts.dir, opts.applicationId)} && npm install`) exec(`cd ${join(opts.dir, opts.applicationId)} && npm install`)
console.log(chalk.green(`Budibase app ${opts.name} created!`)) console.log(chalk.green(`Budibase app ${opts.name} created!`))
} catch (error) { } catch (error) {
console.error(chalk.red("Error creating new app", error)) console.error(
chalk.red("Error creating new app", JSON.stringify(error, { space: 2 }))
)
} }
} }

View File

@ -8,7 +8,7 @@
"type": "node", "type": "node",
"request": "launch", "request": "launch",
"name": "Start Server", "name": "Start Server",
"program": "${workspaceFolder}/src/index.js" "program": "${workspaceFolder}/../cli/bin/budi"
}, },
{ {
"type": "node", "type": "node",
@ -88,6 +88,19 @@
"program": "${workspaceFolder}/node_modules/jest-cli/bin/jest", "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", "type": "node",
"request": "launch", "request": "launch",

View File

@ -1,11 +1,12 @@
const CouchDB = require("../../db") const CouchDB = require("../../db")
const ClientDb = require("../../db/clientDb")
const { getPackageForBuilder } = require("../../utilities/builder") const { getPackageForBuilder } = require("../../utilities/builder")
const uuid = require("uuid") const uuid = require("uuid")
const env = require("../../environment") const env = require("../../environment")
exports.fetch = async function(ctx) { exports.fetch = async function(ctx) {
const clientDb = new CouchDB(`client-${env.CLIENT_ID}`) const db = new CouchDB(ClientDb.name(env.CLIENT_ID))
const body = await clientDb.query("client/by_type", { const body = await db.query("client/by_type", {
include_docs: true, include_docs: true,
key: ["app"], key: ["app"],
}) })
@ -14,13 +15,13 @@ exports.fetch = async function(ctx) {
} }
exports.fetchAppPackage = async function(ctx) { exports.fetchAppPackage = async function(ctx) {
const clientDb = new CouchDB(`client-${env.CLIENT_ID}`) const db = new CouchDB(ClientDb.name(env.CLIENT_ID))
const application = await clientDb.get(ctx.params.applicationId) const application = await db.get(ctx.params.applicationId)
ctx.body = await getPackageForBuilder(ctx.config, application) ctx.body = await getPackageForBuilder(ctx.config, application)
} }
exports.create = async function(ctx) { exports.create = async function(ctx) {
const clientDb = new CouchDB(`client-${env.CLIENT_ID}`) const db = new CouchDB(ClientDb.name(env.CLIENT_ID))
const newApplication = { const newApplication = {
_id: uuid.v4().replace(/-/g, ""), _id: uuid.v4().replace(/-/g, ""),
@ -34,7 +35,7 @@ exports.create = async function(ctx) {
...ctx.request.body, ...ctx.request.body,
} }
const { rev } = await clientDb.post(newApplication) const { rev } = await db.post(newApplication)
newApplication._rev = rev newApplication._rev = rev
ctx.body = newApplication ctx.body = newApplication
ctx.message = `Application ${ctx.request.body.name} created successfully` ctx.message = `Application ${ctx.request.body.name} created successfully`

View File

@ -1,5 +1,6 @@
const jwt = require("jsonwebtoken") const jwt = require("jsonwebtoken")
const CouchDB = require("../../db") const CouchDB = require("../../db")
const ClientDb = require("../../db/clientDb")
const bcrypt = require("../../utilities/bcrypt") const bcrypt = require("../../utilities/bcrypt")
const env = require("../../environment") const env = require("../../environment")
@ -14,7 +15,7 @@ exports.authenticate = async ctx => {
const appId = referer[3] const appId = referer[3]
// find the instance that the user is associated with // 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 app = await db.get(appId)
const instanceId = app.userInstanceMap[username] const instanceId = app.userInstanceMap[username]

View File

@ -1,12 +1,14 @@
const CouchDB = require("../../db") const CouchDB = require("../../db")
const ClientDb = require("../../db/clientDb")
const { resolve, join } = require("path") const { resolve, join } = require("path")
const { const {
budibaseTempDir, budibaseTempDir,
budibaseAppsDir, budibaseAppsDir,
} = require("../../utilities/budibaseDir") } = require("../../utilities/budibaseDir")
const env = require("../../environment")
exports.fetchAppComponentDefinitions = async function(ctx) { 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 app = await db.get(ctx.params.appId)
const componentDefinitions = app.componentLibraries.reduce( const componentDefinitions = app.componentLibraries.reduce(

View File

@ -1,13 +1,12 @@
const CouchDB = require("../../db") const CouchDB = require("../../db")
const client = require("../../db/clientDb")
const uuid = require("uuid") const uuid = require("uuid")
const env = require("../../environment") const env = require("../../environment")
const clientDatabaseId = clientId => `client-${clientId}`
exports.create = async function(ctx) { exports.create = async function(ctx) {
const instanceName = ctx.request.body.name const instanceName = ctx.request.body.name
const uid = uuid.v4().replace(/-/g, "") 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 { applicationId } = ctx.params
const clientId = env.CLIENT_ID const clientId = env.CLIENT_ID
const db = new CouchDB(instanceId) const db = new CouchDB(instanceId)
@ -34,7 +33,7 @@ exports.create = async function(ctx) {
}) })
// Add the new instance under the app clientDB // 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 budibaseApp = await clientDb.get(applicationId)
const instance = { _id: instanceId, name: instanceName } const instance = { _id: instanceId, name: instanceName }
budibaseApp.instances.push(instance) budibaseApp.instances.push(instance)
@ -52,7 +51,7 @@ exports.destroy = async function(ctx) {
// remove instance from client application document // remove instance from client application document
const { metadata } = designDoc 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) const budibaseApp = await clientDb.get(metadata.applicationId)
budibaseApp.instances = budibaseApp.instances.filter( budibaseApp.instances = budibaseApp.instances.filter(
instance => instance !== ctx.params.instanceId instance => instance !== ctx.params.instanceId

View File

@ -4,10 +4,11 @@ const {
budibaseAppsDir, budibaseAppsDir,
budibaseTempDir, budibaseTempDir,
} = require("../../utilities/budibaseDir") } = require("../../utilities/budibaseDir")
const env = require("../../environment")
exports.serveBuilder = async function(ctx) { exports.serveBuilder = async function(ctx) {
let builderPath = resolve(process.cwd(), "builder") let builderPath = resolve(process.cwd(), "builder")
ctx.cookies.set("builder:token", env.ADMIN_SECRET)
await send(ctx, ctx.file, { root: ctx.devPath || builderPath }) await send(ctx, ctx.file, { root: ctx.devPath || builderPath })
} }

View File

@ -1,4 +1,5 @@
const CouchDB = require("../../db") const CouchDB = require("../../db")
const clientDb = require("../../db/clientDb")
const bcrypt = require("../../utilities/bcrypt") const bcrypt = require("../../utilities/bcrypt")
const env = require("../../environment") 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 // the clientDB needs to store a map of users against the app
const clientDb = new CouchDB(`client-${env.CLIENT_ID}`) const db = new CouchDB(clientDb.name(env.CLIENT_ID))
const app = await clientDb.get(appId) const app = await db.get(appId)
app.userInstanceMap = { app.userInstanceMap = {
...app.userInstanceMap, ...app.userInstanceMap,
[username]: ctx.params.instanceId, [username]: ctx.params.instanceId,
} }
await clientDb.put(app) await db.put(app)
ctx.status = 200 ctx.status = 200
ctx.message = "User created successfully." ctx.message = "User created successfully."

View File

@ -4,7 +4,7 @@ const controller = require("../controllers/component")
const router = Router() const router = Router()
router.get( router.get(
"/:clientId/:appId/components/definitions", "/:appId/components/definitions",
controller.fetchAppComponentDefinitions controller.fetchAppComponentDefinitions
) )

View File

@ -1,21 +1,26 @@
const Router = require("@koa/router") const Router = require("@koa/router")
const controller = require("../controllers/static") const controller = require("../controllers/static")
const { budibaseTempDir } = require("../../utilities/budibaseDir") const { budibaseTempDir } = require("../../utilities/budibaseDir")
const env = require("../../environment")
const router = Router() 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 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/componentlibrary", controller.serveComponentLibrary)
.get("/:appId/:file*", controller.serveApp) .get("/:appId/:file*", controller.serveApp)

View File

@ -1,6 +1,9 @@
const { const {
createClientDatabase, createClientDatabase,
supertest createApplication,
destroyClientDatabase,
supertest,
defaultHeaders
} = require("./couchTestUtils") } = require("./couchTestUtils")
describe("/applications", () => { describe("/applications", () => {
@ -9,26 +12,47 @@ describe("/applications", () => {
beforeAll(async () => { beforeAll(async () => {
({ request, server } = await supertest()) ({ request, server } = await supertest())
await createClientDatabase(request)
}); });
beforeEach(async () => {
await createClientDatabase(request)
})
afterEach(async () => {
await destroyClientDatabase(request)
})
afterAll(async () => { afterAll(async () => {
server.close() server.close()
}) })
describe("create", () => { describe("create", () => {
it("returns a success message when the application is successfully created", done => { it("returns a success message when the application is successfully created", async () => {
request const res = await request
.post("/api/applications") .post("/api/applications")
.send({ name: "My App" }) .send({ name: "My App" })
.set("Accept", "application/json") .set(defaultHeaders)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect(200) .expect(200)
.end((err, res) => { expect(res.res.statusMessage).toEqual("Application My App created successfully")
expect(res.res.statusMessage).toEqual("Application My App created successfully") expect(res.body._id).toBeDefined()
expect(res.body._id).toBeDefined() })
done(); })
});
}) 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)
})
})
})

View File

@ -3,7 +3,7 @@ const allDbs = require("pouchdb-all-dbs")
const { budibaseAppsDir } = require("../utilities/budibaseDir") const { budibaseAppsDir } = require("../utilities/budibaseDir")
const env = require("../environment") 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" const isInMemory = env.NODE_ENV === "jest"
if (isInMemory) PouchDB.plugin(require("pouchdb-adapter-memory")) if (isInMemory) PouchDB.plugin(require("pouchdb-adapter-memory"))

View File

@ -1,7 +1,7 @@
const CouchDB = require("./client") const CouchDB = require("./client")
exports.create = async clientId => { exports.create = async clientId => {
const dbId = `client-${clientId}` const dbId = exports.name(clientId)
const db = new CouchDB(dbId) const db = new CouchDB(dbId)
await db.put({ await db.put({
_id: "_design/client", _id: "_design/client",
@ -17,6 +17,10 @@ exports.create = async clientId => {
} }
exports.destroy = async function(clientId) { exports.destroy = async function(clientId) {
const dbId = `client-${clientId}` const dbId = exports.name(clientId)
await new CouchDB(dbId).destroy() await new CouchDB(dbId).destroy()
} }
exports.name = function(clientId) {
return `client_${clientId}`
}

View File

@ -15,6 +15,12 @@ module.exports = async (ctx, next) => {
return 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") const token = ctx.cookies.get("budibase:token")
if (!token) { if (!token) {