removing clientId from frontend, fixing invalid database name

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

View File

@ -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 @@
<AppNotification />
{#if $store.clientId}
<Modal>
<Router {routes} />
</Modal>
{/if}
<Modal>
<Router {routes} />
</Modal>

View File

@ -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()

View File

@ -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

View File

@ -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) {

View File

@ -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)
}

View File

@ -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 }))
)
}
}

View File

@ -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",

View File

@ -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`

View File

@ -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]

View File

@ -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(

View File

@ -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

View File

@ -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 })
}

View File

@ -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."

View File

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

View File

@ -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)

View File

@ -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)
})
})
})

View File

@ -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"))

View File

@ -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}`
}

View File

@ -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) {