Merge pull request #353 from mjashanks/master
Server now support multiple concurrent client databses
This commit is contained in:
commit
3f99d1c761
|
@ -11,7 +11,7 @@ const { exec } = require("child_process")
|
|||
const sqrl = require("squirrelly")
|
||||
|
||||
exports.fetch = async function(ctx) {
|
||||
const db = new CouchDB(ClientDb.name(env.CLIENT_ID))
|
||||
const db = new CouchDB(ClientDb.name(getClientId(ctx)))
|
||||
const body = await db.query("client/by_type", {
|
||||
include_docs: true,
|
||||
key: ["app"],
|
||||
|
@ -21,16 +21,30 @@ exports.fetch = async function(ctx) {
|
|||
}
|
||||
|
||||
exports.fetchAppPackage = async function(ctx) {
|
||||
const db = new CouchDB(ClientDb.name(env.CLIENT_ID))
|
||||
const clientId = await lookupClientId(ctx.params.applicationId)
|
||||
const db = new CouchDB(ClientDb.name(clientId))
|
||||
const application = await db.get(ctx.params.applicationId)
|
||||
ctx.body = await getPackageForBuilder(ctx.config, application)
|
||||
}
|
||||
|
||||
exports.create = async function(ctx) {
|
||||
const db = new CouchDB(ClientDb.name(env.CLIENT_ID))
|
||||
const clientId =
|
||||
(ctx.request.body && ctx.request.body.clientId) || env.CLIENT_ID
|
||||
|
||||
if (!clientId) {
|
||||
ctx.throw(400, "ClientId not suplied")
|
||||
}
|
||||
const appId = newid()
|
||||
// insert an appId -> clientId lookup
|
||||
const masterDb = new CouchDB("clientAppLookup")
|
||||
await masterDb.put({
|
||||
_id: appId,
|
||||
clientId,
|
||||
})
|
||||
const db = new CouchDB(ClientDb.name(clientId))
|
||||
|
||||
const newApplication = {
|
||||
_id: newid(),
|
||||
_id: appId,
|
||||
type: "app",
|
||||
instances: [],
|
||||
userInstanceMap: {},
|
||||
|
@ -47,11 +61,10 @@ exports.create = async function(ctx) {
|
|||
|
||||
const createInstCtx = {
|
||||
params: {
|
||||
clientId: env.CLIENT_ID,
|
||||
applicationId: newApplication._id,
|
||||
},
|
||||
request: {
|
||||
body: { name: `dev-${env.CLIENT_ID}` },
|
||||
body: { name: `dev-${clientId}` },
|
||||
},
|
||||
}
|
||||
await instanceController.create(createInstCtx)
|
||||
|
@ -61,6 +74,7 @@ exports.create = async function(ctx) {
|
|||
await runNpmInstall(newAppFolder)
|
||||
}
|
||||
|
||||
ctx.status = 200
|
||||
ctx.body = newApplication
|
||||
ctx.message = `Application ${ctx.request.body.name} created successfully`
|
||||
}
|
||||
|
@ -79,7 +93,6 @@ const createEmptyAppPackage = async (ctx, app) => {
|
|||
|
||||
if (await exists(newAppFolder)) {
|
||||
ctx.throw(400, "App folder already exists for this application")
|
||||
return
|
||||
}
|
||||
|
||||
await copy(templateFolder, newAppFolder)
|
||||
|
@ -99,6 +112,24 @@ const createEmptyAppPackage = async (ctx, app) => {
|
|||
return newAppFolder
|
||||
}
|
||||
|
||||
const lookupClientId = async appId => {
|
||||
const masterDb = new CouchDB("clientAppLookup")
|
||||
const { clientId } = await masterDb.get(appId)
|
||||
return clientId
|
||||
}
|
||||
|
||||
const getClientId = ctx => {
|
||||
const clientId =
|
||||
(ctx.request.body && ctx.request.body.clientId) ||
|
||||
(ctx.query && ctx.query.clientId) ||
|
||||
env.CLIENT_ID
|
||||
|
||||
if (!clientId) {
|
||||
ctx.throw(400, "ClientId not suplied")
|
||||
}
|
||||
return clientId
|
||||
}
|
||||
|
||||
const updateJsonFile = async (filePath, app) => {
|
||||
const json = await readFile(filePath, "utf8")
|
||||
const newJson = sqrl.Render(json, app)
|
||||
|
|
|
@ -2,7 +2,6 @@ const jwt = require("jsonwebtoken")
|
|||
const CouchDB = require("../../db")
|
||||
const ClientDb = require("../../db/clientDb")
|
||||
const bcrypt = require("../../utilities/bcrypt")
|
||||
const env = require("../../environment")
|
||||
|
||||
exports.authenticate = async ctx => {
|
||||
const { username, password } = ctx.request.body
|
||||
|
@ -10,8 +9,14 @@ exports.authenticate = async ctx => {
|
|||
if (!username) ctx.throw(400, "Username Required.")
|
||||
if (!password) ctx.throw(400, "Password Required")
|
||||
|
||||
const masterDb = new CouchDB("clientAppLookup")
|
||||
const { clientId } = await masterDb.get(ctx.params.appId)
|
||||
|
||||
if (!clientId) {
|
||||
ctx.throw(400, "ClientId not suplied")
|
||||
}
|
||||
// find the instance that the user is associated with
|
||||
const db = new CouchDB(ClientDb.name(env.CLIENT_ID))
|
||||
const db = new CouchDB(ClientDb.name(clientId))
|
||||
const appId = ctx.params.appId
|
||||
const app = await db.get(appId)
|
||||
const instanceId = app.userInstanceMap[username]
|
||||
|
|
|
@ -6,13 +6,26 @@ exports.getClientId = async function(ctx) {
|
|||
}
|
||||
|
||||
exports.create = async function(ctx) {
|
||||
await create(env.CLIENT_ID)
|
||||
const clientId = getClientId(ctx)
|
||||
await create(clientId)
|
||||
ctx.status = 200
|
||||
ctx.message = `Client Database ${env.CLIENT_ID} successfully provisioned.`
|
||||
ctx.message = `Client Database ${clientId} successfully provisioned.`
|
||||
}
|
||||
|
||||
exports.destroy = async function(ctx) {
|
||||
await destroy(env.CLIENT_ID)
|
||||
const clientId = getClientId(ctx)
|
||||
await destroy(clientId)
|
||||
ctx.status = 200
|
||||
ctx.message = `Client Database ${env.CLIENT_ID} successfully deleted.`
|
||||
ctx.message = `Client Database ${clientId} successfully deleted.`
|
||||
}
|
||||
|
||||
const getClientId = ctx => {
|
||||
const clientId =
|
||||
(ctx.query && ctx.query.clientId) ||
|
||||
(ctx.body && ctx.body.clientId) ||
|
||||
env.CLIENT_ID
|
||||
if (!clientId) {
|
||||
ctx.throw(400, "ClientId not suplied")
|
||||
}
|
||||
return clientId
|
||||
}
|
||||
|
|
|
@ -5,10 +5,11 @@ const {
|
|||
budibaseTempDir,
|
||||
budibaseAppsDir,
|
||||
} = require("../../utilities/budibaseDir")
|
||||
const env = require("../../environment")
|
||||
|
||||
exports.fetchAppComponentDefinitions = async function(ctx) {
|
||||
const db = new CouchDB(ClientDb.name(env.CLIENT_ID))
|
||||
const masterDb = new CouchDB("clientAppLookup")
|
||||
const { clientId } = await masterDb.get(ctx.params.appId)
|
||||
const db = new CouchDB(ClientDb.name(clientId))
|
||||
const app = await db.get(ctx.params.appId)
|
||||
|
||||
const componentDefinitions = app.componentLibraries.reduce(
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
const CouchDB = require("../../db")
|
||||
const client = require("../../db/clientDb")
|
||||
const newid = require("../../db/newid")
|
||||
const env = require("../../environment")
|
||||
|
||||
exports.create = async function(ctx) {
|
||||
const instanceName = ctx.request.body.name
|
||||
const appShortId = ctx.params.applicationId.substring(0, 7)
|
||||
const instanceId = `inst_${appShortId}_${newid()}`
|
||||
const { applicationId } = ctx.params
|
||||
const clientId = env.CLIENT_ID
|
||||
|
||||
const masterDb = new CouchDB("clientAppLookup")
|
||||
const { clientId } = await masterDb.get(applicationId)
|
||||
|
||||
const db = new CouchDB(instanceId)
|
||||
await db.put({
|
||||
_id: "_design/database",
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
const CouchDB = require("../../db")
|
||||
const clientDb = require("../../db/clientDb")
|
||||
const bcrypt = require("../../utilities/bcrypt")
|
||||
const env = require("../../environment")
|
||||
const getUserId = userName => `user_${userName}`
|
||||
const {
|
||||
POWERUSER_LEVEL_ID,
|
||||
|
@ -42,8 +41,11 @@ exports.create = async function(ctx) {
|
|||
|
||||
const response = await database.post(user)
|
||||
|
||||
const masterDb = new CouchDB("clientAppLookup")
|
||||
const { clientId } = await masterDb.get(appId)
|
||||
|
||||
// the clientDB needs to store a map of users against the app
|
||||
const db = new CouchDB(clientDb.name(env.CLIENT_ID))
|
||||
const db = new CouchDB(clientDb.name(clientId))
|
||||
const app = await db.get(appId)
|
||||
|
||||
app.userInstanceMap = {
|
||||
|
|
|
@ -5,6 +5,7 @@ const {
|
|||
destroyClientDatabase,
|
||||
builderEndpointShouldBlockNormalUsers,
|
||||
supertest,
|
||||
TEST_CLIENT_ID,
|
||||
defaultHeaders,
|
||||
} = require("./couchTestUtils")
|
||||
|
||||
|
@ -51,6 +52,7 @@ describe("/applications", () => {
|
|||
body: { name: "My App" }
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe("fetch", () => {
|
||||
|
@ -68,6 +70,37 @@ describe("/applications", () => {
|
|||
expect(res.body.length).toBe(2)
|
||||
})
|
||||
|
||||
it("lists only applications in requested client databse", async () => {
|
||||
await createApplication(request, "app1")
|
||||
await createClientDatabase("new_client")
|
||||
|
||||
const blah = await request
|
||||
.post("/api/applications")
|
||||
.send({ name: "app2", clientId: "new_client"})
|
||||
.set(defaultHeaders)
|
||||
.expect('Content-Type', /json/)
|
||||
//.expect(200)
|
||||
|
||||
const client1Res = await request
|
||||
.get(`/api/applications?clientId=${TEST_CLIENT_ID}`)
|
||||
.set(defaultHeaders)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200)
|
||||
|
||||
expect(client1Res.body.length).toBe(1)
|
||||
expect(client1Res.body[0].name).toBe("app1")
|
||||
|
||||
const client2Res = await request
|
||||
.get(`/api/applications?clientId=new_client`)
|
||||
.set(defaultHeaders)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200)
|
||||
|
||||
expect(client2Res.body.length).toBe(1)
|
||||
expect(client2Res.body[0].name).toBe("app2")
|
||||
|
||||
})
|
||||
|
||||
it("should apply authorization to endpoint", async () => {
|
||||
const otherApplication = await createApplication(request)
|
||||
const instance = await createInstance(request, otherApplication._id)
|
||||
|
|
|
@ -9,6 +9,7 @@ const {
|
|||
|
||||
const TEST_CLIENT_ID = "test-client-id"
|
||||
|
||||
exports.TEST_CLIENT_ID = TEST_CLIENT_ID
|
||||
exports.supertest = async () => {
|
||||
let request
|
||||
let port = 4002
|
||||
|
@ -59,7 +60,7 @@ exports.createView = async (request, instanceId, view) => {
|
|||
return res.body
|
||||
}
|
||||
|
||||
exports.createClientDatabase = async () => await create(TEST_CLIENT_ID)
|
||||
exports.createClientDatabase = async id => await create(id || TEST_CLIENT_ID)
|
||||
|
||||
exports.createApplication = async (request, name = "test_application") => {
|
||||
const res = await request
|
||||
|
|
Loading…
Reference in New Issue