add plugins to master app
This commit is contained in:
parent
a782e124e6
commit
80c7df9dae
|
@ -1 +1 @@
|
|||
Subproject commit b372ad7403fa12f92670ef38e7576bc5795006e9
|
||||
Subproject commit feb2f3412a0e3748d6509a3693b1f38c448bd743
|
|
@ -3,11 +3,17 @@ const app = new Koa();
|
|||
const getMasterAppInternal = require("./utilities/masterAppInternal");
|
||||
const router = require("./middleware/routers");
|
||||
const bodyParser = require('koa-bodyparser');
|
||||
const initialiseRuntimeApps = require("./initialise/initialiseRuntimePackages");
|
||||
|
||||
module.exports = async (config) => {
|
||||
|
||||
app.keys = config.keys;
|
||||
app.context.master = await getMasterAppInternal(config);
|
||||
app.context.getAppPackage = await initialiseRuntimeApps(
|
||||
config,
|
||||
app.context.master,
|
||||
config.latestAppsPath
|
||||
)
|
||||
app.use(bodyParser());
|
||||
app.use(router(config, app).routes());
|
||||
return app.listen();
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
{}
|
|
@ -6,5 +6,8 @@ module.exports = () => ({
|
|||
rootPath: "./.data"
|
||||
},
|
||||
keys: ["secret1", "secret2"],
|
||||
port: 4001
|
||||
port: 4001,
|
||||
latestAppsPath: "./appPackages",
|
||||
masterPlugins: {},
|
||||
customizeMaster: appDefinition => appDefinition
|
||||
})
|
|
@ -15,6 +15,15 @@ module.exports = () => ({
|
|||
keys: ["secret1", "secret1"],
|
||||
|
||||
// port for http server to listen on
|
||||
port: 4001
|
||||
port: 4001,
|
||||
|
||||
// path to where your appDefinition etc is stored (dev time)
|
||||
latestAppsPath: "./appPackages",
|
||||
|
||||
// register plugins for master
|
||||
masterPlugins: {},
|
||||
|
||||
// make modifications to master's appdefinition - e.g. add plugins
|
||||
customizeMaster: appDefinition => appDefinition
|
||||
|
||||
})
|
|
@ -4,6 +4,7 @@ const getDatabaseManager = require("../utilities/databaseManager");
|
|||
const {getApisForUser, getApisWithFullAccess} = require("../utilities/budibaseApi");
|
||||
const masterDbAppDefinition = require("../appPackages/master/appDefinition.json");
|
||||
const masterDbAccessLevels = require("../appPackages/master/access_levels.json");
|
||||
const { masterAppPackage } = require("../utilities/createAppPackage");
|
||||
|
||||
module.exports = async (datastoreModule, rootConfig, username, password) => {
|
||||
try {
|
||||
|
@ -18,19 +19,20 @@ module.exports = async (datastoreModule, rootConfig, username, password) => {
|
|||
const templateApi = getTemplateApi({datastore});
|
||||
|
||||
await initialiseData(datastore, {
|
||||
heirarchy:templateApi.constructHeirarchy(masterDbAppDefinition.hierarchy),
|
||||
hierarchy:templateApi.constructHierarchy(masterDbAppDefinition.hierarchy),
|
||||
actions:masterDbAppDefinition.actions,
|
||||
triggers:masterDbAppDefinition.triggers
|
||||
});
|
||||
|
||||
const bbMaster = await getApisWithFullAccess(datastore);
|
||||
const bbMaster = await getApisWithFullAccess(
|
||||
datastore, masterAppPackage());
|
||||
await bbMaster.authApi.saveAccessLevels(masterDbAccessLevels);
|
||||
const user = bbMaster.authApi.getNewUser();
|
||||
user.name = username;
|
||||
user.accessLevels= ["owner"];
|
||||
await bbMaster.authApi.createUser(user, password);
|
||||
|
||||
return await getApisForUser(datastore, username, password);
|
||||
return await getApisForUser(datastore, masterAppPackage(), username, password);
|
||||
} catch(e) {
|
||||
throw e;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
const util = require("util");
|
||||
const fs = require("fs");
|
||||
const { join } = require("path");
|
||||
const { ncp } = require('ncp');
|
||||
const { masterAppPackage } = require("../utilities/createAppPackage");
|
||||
const rimraf = util.promisify(require("rimraf"));
|
||||
const mkdir = util.promisify(fs.mkdir);
|
||||
|
||||
const exists = root => async (path) => {
|
||||
try {
|
||||
await util.promisify(fs.access)(
|
||||
join(root,path)
|
||||
);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const copyfolder = (source, destination) =>
|
||||
new Promise((resolve, reject) => {
|
||||
ncp(source, destination, function (err) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = async (config, bbMaster, latestAppsFolder) => {
|
||||
|
||||
const appsRuntimeFolder = "./runtime_apps";
|
||||
// create runtime folder
|
||||
// copy master into /master/latest
|
||||
if(await exists(appsRuntimeFolder)) {
|
||||
try {
|
||||
await rimraf(appsRuntimeFolder);
|
||||
} catch(err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
|
||||
await mkdir(appsRuntimeFolder);
|
||||
|
||||
|
||||
/*
|
||||
const allApps = await bbMaster
|
||||
.indexApi
|
||||
.listItems("/all_applications");
|
||||
|
||||
for(let app of allApps) {
|
||||
app.
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
const apps = {
|
||||
"_master": masterAppPackage(config)
|
||||
}
|
||||
|
||||
return ((appName, versionId) => {
|
||||
if(appName === "_master") {
|
||||
return apps[appName];
|
||||
}
|
||||
|
||||
return apps[appName][versionId];
|
||||
});
|
||||
}
|
|
@ -166,14 +166,14 @@ module.exports = (config, app) => {
|
|||
);
|
||||
ctx.response.status = StatusCodes.OK;
|
||||
})
|
||||
.post("/:appname/api/appHeirarchy", async (ctx) => {
|
||||
ctx.body = await ctx.instance.templateApi.saveApplicationHeirarchy(
|
||||
.post("/:appname/api/apphierarchy", async (ctx) => {
|
||||
ctx.body = await ctx.instance.templateApi.saveApplicationHierarchy(
|
||||
ctx.body
|
||||
);
|
||||
ctx.response.status = StatusCodes.OK;
|
||||
})
|
||||
.post("/:appname/api/actionsAndTriggers", async (ctx) => {
|
||||
ctx.body = await ctx.instance.templateApi.saveApplicationHeirarchy(
|
||||
ctx.body = await ctx.instance.templateApi.saveApplicationHierarchy(
|
||||
ctx.body
|
||||
);
|
||||
ctx.response.status = StatusCodes.OK;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
"koa-bodyparser": "^4.2.1",
|
||||
"koa-router": "^7.4.0",
|
||||
"koa-session": "^5.12.0",
|
||||
"ncp": "^2.0.0",
|
||||
"rimraf": "^2.6.3",
|
||||
"yargs": "^13.2.4"
|
||||
},
|
||||
|
@ -27,7 +28,7 @@
|
|||
"server-destroy": "^1.0.1",
|
||||
"supertest": "^4.0.2"
|
||||
},
|
||||
"jest" : {
|
||||
"jest": {
|
||||
"testEnvironment": "node"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
const statusCodes = require("../utilities/statusCodes");
|
||||
const util = require("util");
|
||||
const fs = require("fs");
|
||||
const readFile = util.promisify(fs.readFile);
|
||||
|
||||
module.exports = (app) => {
|
||||
|
||||
|
@ -41,7 +44,7 @@ module.exports = (app) => {
|
|||
});
|
||||
|
||||
const testUserName = "test_user";
|
||||
const testPassword = "test_user_password";
|
||||
let testPassword = "test_user_password";
|
||||
it("should be able to create new user with authenticated cookie", async () => {
|
||||
|
||||
await app.post("/_master/api/createUser", {
|
||||
|
@ -120,4 +123,30 @@ module.exports = (app) => {
|
|||
})
|
||||
.expect(statusCodes.OK);
|
||||
});
|
||||
|
||||
it("should be able to reset password with temporary access", async () => {
|
||||
// need to sort out behaviour sources for this...
|
||||
await app.post("/_master/api/createTemporaryAccess", {
|
||||
username: testUserName
|
||||
})
|
||||
.expect(statusCodes.OK);
|
||||
|
||||
testPassword = "test_user_new_password";
|
||||
|
||||
const tempCode = await readFile(`tempaccess${testUserName}`, "utf8");
|
||||
|
||||
await app.post("/_master/api/setPasswordFromTemporaryCode", {
|
||||
username: testUserName,
|
||||
tempCode,
|
||||
newPassword:testPassword
|
||||
})
|
||||
.expect(statusCodes.OK);
|
||||
|
||||
await app.post("/_master/api/authenticate", {
|
||||
username: testUserName,
|
||||
password: testPassword
|
||||
})
|
||||
.expect(statusCodes.OK);
|
||||
|
||||
});
|
||||
};
|
||||
|
|
|
@ -10,13 +10,42 @@ const mkdir = promisify(fs.mkdir);
|
|||
const masterOwnerName = "test_master";
|
||||
const masterOwnerPassword = "test_master_pass";
|
||||
|
||||
const masterPlugins = {
|
||||
main: {
|
||||
outputToFile : ({filename, content}) => {
|
||||
fs.writeFile(`./tests/${filename}`, content, {encoding:"utf8"});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const customizeMaster = appDefinition => {
|
||||
|
||||
appDefinition.actions.outputToFile = {
|
||||
name: 'outputToFile',
|
||||
behaviourSource: 'main',
|
||||
behaviourName: 'outputToFile',
|
||||
initialOptions: {}
|
||||
};
|
||||
|
||||
appDefinition.triggers.push({
|
||||
actionName: 'outputToFile',
|
||||
eventName: 'authApi:createTemporaryAccess:onComplete',
|
||||
optionsCreator: 'return ({filename:"tempaccess" + context.userName, content:context.result})',
|
||||
condition: ''
|
||||
});
|
||||
|
||||
return appDefinition;
|
||||
}
|
||||
|
||||
const config = {
|
||||
datastore: "local",
|
||||
datastoreConfig: {
|
||||
rootPath: "./tests/.data"
|
||||
},
|
||||
keys: ["secret1", "secret2"],
|
||||
port: 4002
|
||||
port: 4002,
|
||||
masterPlugins,
|
||||
customizeMaster
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,11 +1,25 @@
|
|||
const crypto = require("../nodeCrypto");
|
||||
const {getAppApis} = require("budibase-core");
|
||||
const {getAppApis, getTemplateApi} = require("budibase-core");
|
||||
|
||||
const constructHierarchy = (datastore, appDefinition) => {
|
||||
appDefinition.hierarchy = getTemplateApi({datastore})
|
||||
.constructHierarchy(appDefinition.hierarchy);
|
||||
return appDefinition;
|
||||
}
|
||||
|
||||
module.exports.getApisWithFullAccess = async (datastore, appPackage) => {
|
||||
|
||||
const appDefinition = constructHierarchy(
|
||||
datastore,
|
||||
appPackage.appDefinition);
|
||||
|
||||
module.exports.getApisWithFullAccess = async (datastore) => {
|
||||
const bb = await getAppApis(
|
||||
datastore,
|
||||
null, null, null,
|
||||
crypto
|
||||
appPackage.behaviourSources,
|
||||
null, //cleanupTransations
|
||||
null, // getEpochTime
|
||||
crypto,
|
||||
appDefinition
|
||||
);
|
||||
|
||||
bb.withFullAccess();
|
||||
|
@ -13,11 +27,16 @@ module.exports.getApisWithFullAccess = async (datastore) => {
|
|||
return bb;
|
||||
};
|
||||
|
||||
module.exports.getApisForUser = async (datastore, username, password) => {
|
||||
module.exports.getApisForUser = async (datastore, appPackage, username, password) => {
|
||||
const bb = await getAppApis(
|
||||
datastore,
|
||||
null, null, null,
|
||||
crypto
|
||||
appPackage.behaviourSources,
|
||||
null, //cleanupTransations
|
||||
null, // getEpochTime
|
||||
crypto,
|
||||
constructHierarchy(
|
||||
datastore,
|
||||
appPackage.appDefinition)
|
||||
);
|
||||
|
||||
await bb.authenticateAs(username, password);
|
||||
|
@ -25,14 +44,19 @@ module.exports.getApisForUser = async (datastore, username, password) => {
|
|||
return bb;
|
||||
}
|
||||
|
||||
module.exports.getApisForSession = async (datastore, session) => {
|
||||
module.exports.getApisForSession = async (datastore, appPackage, session) => {
|
||||
|
||||
const user = JSON.parse(session.user_json);
|
||||
|
||||
const bb = await getAppApis(
|
||||
datastore,
|
||||
null, null, null,
|
||||
crypto
|
||||
appPackage.behaviourSources,
|
||||
null, //cleanupTransations
|
||||
null, // getEpochTime
|
||||
crypto,
|
||||
constructHierarchy(
|
||||
datastore,
|
||||
appPackage.appDefinition)
|
||||
);
|
||||
|
||||
bb.asUser(user);
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
const { join } = require("path");
|
||||
|
||||
const createAppPackage = (appPath) => ({
|
||||
appDefinition: require(join(appPath, "appDefinition.json")),
|
||||
behaviourSources: require(join(appPath, "plugins.json")),
|
||||
appPath
|
||||
});
|
||||
|
||||
module.exports.masterAppPackage = (config) => {
|
||||
const standardPackage = createAppPackage("../appPackages/master");
|
||||
|
||||
const customizeMaster = config && config.customizeMaster
|
||||
? config.customizeMaster
|
||||
: a => a;
|
||||
|
||||
const appDefinition = customizeMaster(
|
||||
standardPackage.appDefinition);
|
||||
|
||||
return ({
|
||||
appDefinition,
|
||||
behaviourSources: config && config.masterPlugins
|
||||
? config.masterPlugins
|
||||
: standardPackage.behaviourSources,
|
||||
appPath: standardPackage.appPath
|
||||
});
|
||||
}
|
||||
|
||||
module.exports.applictionVersionPackage = (appname, versionId) =>
|
||||
createAppPackage(`../runtimePackages/${appname}/${versionId}`);
|
||||
|
||||
|
|
@ -1,9 +1,10 @@
|
|||
const {getApisWithFullAccess, getApisForSession} = require("./budibaseApi");
|
||||
const getDatastore = require("./datastore");
|
||||
const getDatabaseManager = require("./databaseManager");
|
||||
const {$} = require("budibase-core").common;
|
||||
const {keyBy} = require("lodash/fp");
|
||||
const {$, splitKey} = require("budibase-core").common;
|
||||
const { keyBy, last } = require("lodash/fp");
|
||||
const {unauthorized} = require("./exceptions");
|
||||
const { masterAppPackage, applictionVersionPackage } = require("../utilities/createAppPackage");
|
||||
|
||||
const isMaster = appname => appname === "_master";
|
||||
|
||||
|
@ -19,7 +20,8 @@ module.exports = async (config) => {
|
|||
const masterDatastore = datastoreModule.getDatastore(
|
||||
databaseManager.masterDatastoreConfig);
|
||||
|
||||
const bb = await getApisWithFullAccess(masterDatastore);
|
||||
const bb = await getApisWithFullAccess(
|
||||
masterDatastore, masterAppPackage(config));
|
||||
|
||||
let applications;
|
||||
const loadApplications = async () =>
|
||||
|
@ -94,8 +96,15 @@ module.exports = async (config) => {
|
|||
const instance = await bb.recordApi.load(
|
||||
userInMaster.instance.key);
|
||||
|
||||
const versionId = $(instance.version.key, [
|
||||
splitKey,
|
||||
last
|
||||
]);
|
||||
|
||||
const bbInstance = await getApisWithFullAccess(
|
||||
datastoreModule.getDatastore(instance.datastoreconfig));
|
||||
datastoreModule.getDatastore(instance.datastoreconfig),
|
||||
applictionVersionPackage(appname, versionId)
|
||||
);
|
||||
|
||||
const authUser = await bbInstance.authApi.authenticate(username, password);
|
||||
|
||||
|
@ -117,7 +126,11 @@ module.exports = async (config) => {
|
|||
const customId = bb.recordApi.customId("mastersession", sessionId);
|
||||
try {
|
||||
const session = await bb.recordApi.load(`/sessions/${customId}`);
|
||||
return await getApisForSession(masterDatastore, session);
|
||||
return await getApisForSession(
|
||||
masterDatastore,
|
||||
masterAppPackage(config),
|
||||
session);
|
||||
|
||||
} catch(_) {
|
||||
return null;
|
||||
}
|
||||
|
@ -128,7 +141,10 @@ module.exports = async (config) => {
|
|||
try {
|
||||
const session = await bb.recordApi.load(`/applications/${app.id}/sessions/${customId}`);
|
||||
const instanceDatastore = getInstanceDatastore(session.instanceDatastoreConfig)
|
||||
return await getApisForSession(instanceDatastore, session);
|
||||
return await getApisForSession(
|
||||
instanceDatastore,
|
||||
applictionVersionPackage(appname, session.instanceVersion),
|
||||
session);
|
||||
} catch(_) {
|
||||
return null;
|
||||
}
|
||||
|
@ -203,7 +219,8 @@ module.exports = async (config) => {
|
|||
authenticate,
|
||||
getInstanceApiForSession,
|
||||
getFullAccessInstanceApiForUsername,
|
||||
removeSessionsForUser
|
||||
removeSessionsForUser,
|
||||
bbMaster:bb
|
||||
});
|
||||
|
||||
}
|
|
@ -2667,6 +2667,11 @@ natural-compare@^1.4.0:
|
|||
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
|
||||
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
|
||||
|
||||
ncp@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3"
|
||||
integrity sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=
|
||||
|
||||
needle@^2.2.1:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c"
|
||||
|
|
Loading…
Reference in New Issue