1
0
Fork 0
mirror of synced 2024-06-26 18:10:51 +12:00

add plugins to master app

This commit is contained in:
michael shanks 2019-06-25 22:48:22 +01:00
parent a782e124e6
commit 80c7df9dae
15 changed files with 255 additions and 29 deletions

@ -1 +1 @@
Subproject commit b372ad7403fa12f92670ef38e7576bc5795006e9
Subproject commit feb2f3412a0e3748d6509a3693b1f38c448bd743

View file

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

View file

@ -0,0 +1 @@
{}

View file

@ -6,5 +6,8 @@ module.exports = () => ({
rootPath: "./.data"
},
keys: ["secret1", "secret2"],
port: 4001
port: 4001,
latestAppsPath: "./appPackages",
masterPlugins: {},
customizeMaster: appDefinition => appDefinition
})

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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