1
0
Fork 0
mirror of synced 2024-06-27 02:20:35 +12:00

injecting plugins into child apps

This commit is contained in:
michael shanks 2019-07-09 07:29:50 +01:00
parent 1590b584d4
commit 991bd69671
23 changed files with 260 additions and 56 deletions

View file

@ -1,19 +1,19 @@
const Koa = require('koa');
const app = new Koa();
const getMasterAppInternal = require("./utilities/masterAppInternal");
const router = require("./middleware/routers");
const koaBody = require('koa-body');
const initialiseRuntimePackages = require("./initialise/initialiseRuntimePackages");
module.exports = async (config) => {
module.exports = async (budibaseContext) => {
const { config } = budibaseContext;
app.keys = config.keys;
app.context.master = await getMasterAppInternal(config);
app.context.master = budibaseContext.master;
app.context.getAppPackage = await initialiseRuntimePackages(
config,
budibaseContext,
app.context.master,
config.latestAppsPath
)
);
app.use(koaBody({ multipart : true }));
app.use(router(config, app).routes());
return app.listen();

View file

@ -74,6 +74,16 @@
"getInitialValue": "default",
"getUndefinedValue": "default"
},
{
"name": "createdByMaster",
"type": "bool",
"typeOptions": {
"allowNulls": false
},
"label": "Created by Master",
"getInitialValue": "default",
"getUndefinedValue": "default"
},
{
"name": "instance",
"type": "reference",
@ -273,6 +283,18 @@
"getInitialValue": "default",
"getUndefinedValue": "default"
},
{
"name": "instanceKey",
"type": "string",
"typeOptions": {
"maxLength": null,
"values": null,
"allowDeclaredValuesOnly": false
},
"label": "Instance Key",
"getInitialValue": "default",
"getUndefinedValue": "default"
},
{
"name": "instanceVersion",
"type": "string",
@ -467,7 +489,7 @@
"actionName": "create_user",
"eventName": "recordApi:save:onRecordCreated",
"optionsCreator": "return ({ user:context.record, apis });",
"condition": "context.record.type === \"user\""
"condition": "context.record.type === \"user\" && context.record.createdByMaster === true"
}
]
}

View file

@ -11,7 +11,8 @@ const { createWriteStream } = require("fs");
const { applictionVersionPackage } = require("../../utilities/createAppPackage");
const { getApisWithFullAccess } = require("../../utilities/budibaseApi");
module.exports = (config) => {
module.exports = (context) => {
const { config } = context;
const datastoreModule = require(`../../../datastores/datastores/${config.datastore}`);
return ({
initialiseInstance : async ({ instance, apis }) => {
@ -36,9 +37,8 @@ module.exports = (config) => {
await downloadAppPackage(apis, instance, application.name, versionId);
const dbConfig = await createInstanceDb(
config,
context,
datastoreModule,
config.datastoreConfig,
application,
instance
);
@ -67,10 +67,11 @@ module.exports = (config) => {
last,
]);
const appPackage = applictionVersionPackage(
config,
const appPackage = await applictionVersionPackage(
context,
application.name,
versionId);
versionId,
instance.key);
const instanceApis = await getApisWithFullAccess(
datastoreModule.getDatastore(

View file

@ -1,4 +1,6 @@
const app = require("./app");
const config = require("./config");
const buildAppContext = require("./initialise/buildAppContext");
app(config);
buildAppContext(config, true)
.then((appContext) => app(appContext));

View file

@ -0,0 +1,11 @@
const getMasterAppInternal = require("../utilities/masterAppInternal");
module.exports = async (config, masterIsCreated) => {
const context = { config };
if(!masterIsCreated) return context;
const master = await getMasterAppInternal(context);
context.master = master;
return context;
};

View file

@ -3,19 +3,18 @@ const {
setupDatastore,
common
} = require("budibase-core");
const constructHierarchy = require("../utilities/constructHierarchy");
const getDatabaseManager = require("../utilities/databaseManager");
const masterDbAppDefinition = require("../appPackages/master/appDefinition.json");
const { applictionVersionPackage } = require("../utilities/createAppPackage");
const { last } = require("lodash/fp");
const {$,splitKey} = common;
module.exports = async (config, datastoreModule, rootDatastoreConfig, app, instance) => {
module.exports = async (context, datastoreModule, app, instance) => {
try {
const databaseManager = getDatabaseManager(
datastoreModule, rootDatastoreConfig);
datastoreModule,
context.config.datastoreConfig);
await databaseManager.createEmptyInstanceDb(
app.id, instance.id);
@ -31,8 +30,8 @@ module.exports = async (config, datastoreModule, rootDatastoreConfig, app, insta
last
]);
const appPackage = applictionVersionPackage(
config, app.name, versionId
const appPackage = await applictionVersionPackage(
context, app.name, versionId, instance.key
);
await initialiseData(

View file

@ -6,9 +6,11 @@ const masterDbAppDefinition = require("../appPackages/master/appDefinition.json"
const masterDbAccessLevels = require("../appPackages/master/access_levels.json");
const { masterAppPackage } = require("../utilities/createAppPackage");
module.exports = async (datastoreModule, rootDatastoreConfig, username, password, budibaseConfig) => {
module.exports = async (context, datastoreModule, username, password) => {
try {
const databaseManager = getDatabaseManager(datastoreModule, rootDatastoreConfig);
const { config } = context;
const databaseManager = getDatabaseManager(
datastoreModule, config.datastoreConfig);
await databaseManager.createEmptyMasterDb();
const masterDbConfig = databaseManager.masterDatastoreConfig;
@ -19,15 +21,20 @@ module.exports = async (datastoreModule, rootDatastoreConfig, username, password
await initialiseData(datastore,
constructHierarchy(masterDbAppDefinition));
const masterPackage = masterAppPackage(context);
const bbMaster = await getApisWithFullAccess(
datastore, masterAppPackage(budibaseConfig));
datastore, masterPackage);
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, masterAppPackage(budibaseConfig), username, password);
return await getApisForUser(
datastore,
masterPackage,
username,
password);
} catch(e) {
throw e;
}

View file

@ -4,7 +4,7 @@ const readline = require('readline');
const { promisify } = require('util');
const { mkdir, rimraf } = require("../utilities/fsawait");
const budibaseConfig = require("../config");
const buildAppContext = require("../initialise/buildAppContext");
readline.Interface.prototype.question[promisify.custom] = function(prompt) {
@ -67,10 +67,10 @@ const question = async (q) => {
await mkdir(rootconfig.rootPath);
}
const appContext = await buildAppContext(budibaseConfig, false);
await create(
datastoreModule,
rootconfig,
username,
password,
budibaseConfig)
appContext,
datastoreModule,
username,
password);
})()

View file

@ -15,7 +15,7 @@ const copyfolder = (source, destination) =>
});
module.exports = async (config, bbMaster, latestAppsFolder) => {
module.exports = async (context, bbMaster, latestAppsFolder) => {
// create runtime folder
// copy master into /master/latest
@ -42,7 +42,7 @@ module.exports = async (config, bbMaster, latestAppsFolder) => {
const apps = {
"_master": masterAppPackage(config)
"_master": masterAppPackage(context)
}
return ((appName, versionId) => {

View file

@ -52,7 +52,6 @@ module.exports = (app, appName) => {
name: testUserName,
accessLevels:["owner"],
enabled:true
},
password: testPassword
})

View file

@ -86,7 +86,7 @@ module.exports = (app) => {
user1_instance1 = master.recordApi
.getNew(`${newAppKey}/users`, "user");
user1_instance1.name = app.credentials.testApp.username;
user1_instance1.createdByMaster = true;
/*const lookupResponse = await app.get(`/_master/api/lookup_field/${user1_instance1.key}?fields=instance`)
.set("cookie", app.credentials._master.cookie)

View file

@ -4,7 +4,7 @@ const createMasterDb = require("../initialise/createMasterDb");
const request = require("supertest");
const fs = require("fs");
const { masterAppPackage } = require("../utilities/createAppPackage");
const buildAppContext = require("../initialise/buildAppContext");
var enableDestroy = require('server-destroy');
const masterOwnerName = "test_master";
@ -58,7 +58,8 @@ module.exports = () => {
start: async () => {
try {
await reInitialize();
server = await app(config);
const budibaseContext = await buildAppContext(config, true);
server = await app(budibaseContext);
} catch(e) {
console.log(e.message);
}
@ -85,7 +86,7 @@ module.exports = () => {
name: "testApp"
},
destroy: () => server.destroy(),
masterAppPackage: masterAppPackage(config)
masterAppPackage: masterAppPackage({ config })
})
};
@ -110,12 +111,13 @@ const reInitialize = async () => {
await mkdir(config.datastoreConfig.rootPath);
const datastoreModule = require("../../datastores/datastores/" + config.datastore);
const budibaseContext = await buildAppContext(config, false);
await createMasterDb(
budibaseContext,
datastoreModule,
config.datastoreConfig,
masterOwnerName,
masterOwnerPassword ,
config
masterOwnerPassword
);
}

View file

@ -1,5 +1,9 @@
const crypto = require("../nodeCrypto");
const {getAppApis, getTemplateApi} = require("budibase-core");
const getDatastore = require("./datastore");
const { masterAppPackage } = require("../utilities/createAppPackage");
const getDatabaseManager = require("../utilities/databaseManager");
const constructHierarchy = (datastore, appDefinition) => {
appDefinition.hierarchy = getTemplateApi({datastore})
@ -62,4 +66,20 @@ module.exports.getApisForSession = async (datastore, appPackage, session) => {
bb.asUser(user);
return bb;
}
module.exports.getMasterApisWithFullAccess = async (context) => {
const { config } = context;
const datastoreModule = getDatastore(config);
const databaseManager = getDatabaseManager(
datastoreModule,
config.datastoreConfig);
const masterDatastore = datastoreModule.getDatastore(
databaseManager.masterDatastoreConfig);
return await module.exports.getApisWithFullAccess(
masterDatastore, masterAppPackage(context));
}

View file

@ -2,7 +2,9 @@ const { join } = require("path");
const constructHierarchy = require("./constructHierarchy");
const { common } = require("budibase-core");
const { getRuntimePackageDirectory } = require("../utilities/runtimePackages");
const createAppPackage = (config, appPath) => {
const injectPlugins = require("./injectedPlugins");
const createAppPackage = (context, appPath) => {
const appDefModule = require(
join(appPath, "appDefinition.json"));
@ -16,14 +18,15 @@ const createAppPackage = (config, appPath) => {
return ({
appDefinition: appDefModule,
behaviourSources: pluginsModule(config),
behaviourSources: pluginsModule(context),
appPath,
accessLevels
})
}
module.exports.masterAppPackage = (config) => {
const standardPackage = createAppPackage(config, "../appPackages/master");
module.exports.masterAppPackage = (context) => {
const { config } = context;
const standardPackage = createAppPackage(context, "../appPackages/master");
const customizeMaster = config && config.customizeMaster
? config.customizeMaster
@ -35,7 +38,7 @@ module.exports.masterAppPackage = (config) => {
]);
const plugins = require("../appPackages/master/plugins.js")
(config);
(context);
return ({
appDefinition,
@ -46,11 +49,17 @@ module.exports.masterAppPackage = (config) => {
});
}
module.exports.applictionVersionPackage = (config, appname, versionId) => {
module.exports.applictionVersionPackage = async (context, appname, versionId, instanceKey) => {
const pkg = createAppPackage(
config,
context,
join("..", getRuntimePackageDirectory(appname, versionId))
);
pkg.appDefinition = constructHierarchy(pkg.appDefinition);
await injectPlugins(
pkg,
context.master,
appname,
instanceKey
);
return pkg;
}

View file

@ -0,0 +1,17 @@
module.exports = ({ masterAppInternal, instanceKey }) => async ({ user }) => {
const { bbMaster } = masterAppInternal;
const masterUser = bbMaster.recordApi
.getNew(`${newAppKey}/users`, "user");
masterUser.name = user.name;
masterUser.createdByMaster = false;
masterUser.instance = await bbMaster.recordApi
.load(instanceKey);
masterUser.active = user.enabled;
await bbMaster.recordApi.save(masterUser);
}

View file

@ -0,0 +1,6 @@
module.exports = ({ masterAppInternal, app }) => async ({ username }) => {
await masterAppInternal.disableUser(
app, username
);
}

View file

@ -0,0 +1,6 @@
module.exports = ({ masterAppInternal, app }) => async ({ username }) => {
await masterAppInternal.enableUser(
app, username
);
}

View file

@ -0,0 +1,77 @@
const createUser = require("./createUser");
const enableUser = require("./enableUser");
const disableUser = require("./disableUser");
module.exports = async (appPackage, masterAppInternal, instanceKey, appName) => {
const plugin = await constructPlugin(
masterAppInternal,
appName,
instanceKey
);
appPackage.behaviourSources._injected = plugin;
createActions(appPackage);
createTriggers(appPackage);
}
const createTriggers = (appPackage) => {
const appDef = appPackage.appDefinition;
appDef.triggers.push({
actionName: 'createUser',
eventName: 'authApi:createUser:onComplete',
optionsCreator: 'return {user:context.user};',
condition: ''
});
appDef.triggers.push({
actionName: 'enableUser',
eventName: 'authApi:enableUser:onComplete',
optionsCreator: 'return {username:context.username};',
condition: ''
});
appDef.triggers.push({
actionName: 'disableUser',
eventName: 'authApi:disableUser:onComplete',
optionsCreator: 'return {username:context.username};',
condition: ''
});
}
const createActions = (appPackage) => {
const appDef = appPackage.appDefinition;
appDef.actions.createUser = {
name: "createUser",
behaviourSource: '_injected',
behaviourName: 'createUser',
initialOptions: {}
};
appDef.actions.createUser = {
name: "enableUser",
behaviourSource: '_injected',
behaviourName: 'enableUser',
initialOptions: {}
};
appDef.actions.createUser = {
name: "disableUser",
behaviourSource: '_injected',
behaviourName: 'disableUser',
initialOptions: {}
};
}
const constructPlugin = async (masterAppInternal, appName, instanceKey) => {
const app = await masterAppInternal.getApplication(appName);
const initialiseObj = {
masterAppInternal, app, instanceKey
};
return ({
createUser:createUser(initialiseObj),
enableUser:enableUser(initialiseObj),
disableUser:disableUser(initialiseObj)
});
}

View file

@ -1,27 +1,29 @@
const {getApisWithFullAccess, getApisForSession} = require("./budibaseApi");
const {
getApisWithFullAccess,
getApisForSession,
getMasterApisWithFullAccess
} = require("./budibaseApi");
const getDatastore = require("./datastore");
const getDatabaseManager = require("./databaseManager");
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";
module.exports = async (config) => {
module.exports = async (context) => {
const { config } = context;
const datastoreModule = getDatastore(config);
const databaseManager = getDatabaseManager(
datastoreModule,
config.datastoreConfig);
const masterDatastore = datastoreModule.getDatastore(
databaseManager.masterDatastoreConfig);
const bb = await getApisWithFullAccess(
masterDatastore, masterAppPackage(config));
const bb = await getMasterApisWithFullAccess(context);
let applications;
const loadApplications = async () =>
@ -100,9 +102,11 @@ module.exports = async (config) => {
]);
const dsConfig = JSON.parse(instance.datastoreconfig);
const appPackage = await applictionVersionPackage(
context, appname, versionId, instance.key);
const bbInstance = await getApisWithFullAccess(
datastoreModule.getDatastore(dsConfig),
applictionVersionPackage(config, appname, versionId)
appPackage
);
const authUser = await bbInstance.authApi.authenticate(username, password);
@ -115,6 +119,7 @@ module.exports = async (config) => {
bb.recordApi.setCustomId(session, sessionId);
session.user_json = JSON.stringify(authUser);
session.instanceDatastoreConfig = instance.datastoreconfig;
session.instanceKey = instance.key;
session.username = username;
session.instanceVersion = instance.version.key;
await bb.recordApi.save(session);
@ -128,7 +133,7 @@ module.exports = async (config) => {
const session = await bb.recordApi.load(`/sessions/${customId}`);
return await getApisForSession(
masterDatastore,
masterAppPackage(config),
masterAppPackage(context),
session);
} catch(_) {
@ -147,9 +152,12 @@ module.exports = async (config) => {
last
]);
const appPackage = await applictionVersionPackage(
context, appname, versionId, session.instanceKey);
return await getApisForSession(
instanceDatastore,
applictionVersionPackage(config, appname, versionId),
appPackage,
session);
} catch(_) {
return null;
@ -190,10 +198,13 @@ module.exports = async (config) => {
splitKey,
last
]);
const appPackage = await applictionVersionPackage(
context, appname, versionId, user.instanceKey);
return await getApisWithFullAccess(
instanceDatastore,
applictionVersionPackage(config, appname, versionId));
appPackage);
}
};
@ -230,6 +241,19 @@ module.exports = async (config) => {
}
}
const disableUser = async (app, username) => {
await removeSessionsForUser(appName, username);
const userInMaster = await getUser(bb, app.id, username);
userInMaster.active = false;
await bb.recordApi.save(userInMaster);
}
const enableUser = async (app, username) => {
const userInMaster = await getUser(bb, app.id, username);
userInMaster.active = true;
await bb.recordApi.save(userInMaster);
}
return ({
getApplication,
getSession,
@ -238,6 +262,8 @@ module.exports = async (config) => {
getInstanceApiForSession,
getFullAccessInstanceApiForUsername,
removeSessionsForUser,
disableUser,
enableUser,
bbMaster:bb
});