diff --git a/packages/core b/packages/core index 11c29ab2c..804483d3a 160000 --- a/packages/core +++ b/packages/core @@ -1 +1 @@ -Subproject commit 11c29ab2c467ea7aea0161f331dab07694ccd0ab +Subproject commit 804483d3a3210936743f3b57a032783296eab06c diff --git a/packages/datastores/datastores/local.js b/packages/datastores/datastores/local.js index 4dbb053cd..8e770709e 100644 --- a/packages/datastores/datastores/local.js +++ b/packages/datastores/datastores/local.js @@ -3,8 +3,8 @@ const fs = require("fs"); const {join} = require("path"); const readFile = promisify(fs.readFile); -const writeFile = (path, content) => - promisify(fs.writeFile)(path, content, "utf8"); +const writeFile = (path, content, overwrite) => + promisify(fs.writeFile)(path, content, {encoding:"utf8", flag: overwrite ? "w" : "wx"}); const access = promisify(fs.access); const mkdir = promisify(fs.mkdir); const rmdir = promisify(fs.rmdir); @@ -16,10 +16,16 @@ const stat = promisify(fs.stat); const updateFile = root => async (path, file) => await writeFile( join(root,path), - file + file, + true ); -const createFile = updateFile; +const createFile = root => async (path, file) => + await writeFile( + join(root,path), + file, + false + ); const loadFile = root => async (path) => await readFile( diff --git a/packages/server/appPackages/master/appDefinition.json b/packages/server/appPackages/master/appDefinition.json index f9a0d7b6d..7487ae21b 100644 --- a/packages/server/appPackages/master/appDefinition.json +++ b/packages/server/appPackages/master/appDefinition.json @@ -53,7 +53,7 @@ "type": "record", "fields": [ { - "name": "unique_name", + "name": "name", "type": "string", "typeOptions": { "maxLength": 200, @@ -329,7 +329,7 @@ { "name": "user_name_lookup", "type": "index", - "map": "return {name:record.name, instanceDatastoreConfig:instance.datastoreconfig};", + "map": "return ({name:record.name, instanceKey:record.instance.key ? record.instance.key : '', instanceDatastoreConfig:record.instance.datastoreconfig ? record.instance.datastoreconfig : 'nothing'});", "filter": "", "indexType": "ancestor", "getShardName": "return record.name.substring(0,2)", @@ -448,8 +448,8 @@ { "actionName": "initialise_instance", "eventName": "recordApi:save:onRecordCreated", - "optionsCreator": "return { instance:context.record, apis };", - "condition": "record.type === \"instance\"" + "optionsCreator": "return ({ instance:context.record, apis });", + "condition": "context.record.type === \"instance\"" }, { "actionName": "create_user", diff --git a/packages/server/appPackages/master/main.js b/packages/server/appPackages/master/main.js index d29bc6f44..bc6f1b36d 100644 --- a/packages/server/appPackages/master/main.js +++ b/packages/server/appPackages/master/main.js @@ -1,7 +1,7 @@ const { tmpdir } = require("os"); const { join } = require("path"); const uuid = require("uuid/v1"); -const { take, takeRight } = require("lodash/fp"); +const { take, takeRight, last } = require("lodash/fp"); const { splitKey, $, joinKey } = require("budibase-core").common; const { unzipTarGzPackageToRuntime } = require("../../utilities/targzAppPackage"); const { getRuntimePackageDirectory } = require("../../utilities/runtimePackages"); @@ -32,24 +32,25 @@ module.exports = (config) => { const versionId = $(instance.version.key, [ splitKey, - takeRight(1), - joinKey + last ]); const runtimeDir = getRuntimePackageDirectory( application.name, versionId); - + if(!await exists(runtimeDir)) await downloadAppPackage(apis, instance, application.name, versionId); instance.datastoreconfig = JSON.stringify(dbConfig); instance.isNew = false; - await apis.recordApi.save(instance); + instance.transactionId = ""; + + await apis.recordApi.save(instance); }, createNewUser: async ({user, apis}) => { - const instance = apis.recordApi.load(user.instance.key); + const instance = await apis.recordApi.load(user.instance.key); const appKey = $(instance.key, [ splitKey, @@ -61,16 +62,17 @@ module.exports = (config) => { const versionId = $(instance.version.key, [ splitKey, - takeRight(1), - joinKey + last, ]); const appPackage = applictionVersionPackage( + config, application.name, versionId); - const instanceApis = getApisWithFullAccess( - datastoreModule.getDatastore(instance.datastoreconfig), + const instanceApis = await getApisWithFullAccess( + datastoreModule.getDatastore( + JSON.parse(instance.datastoreconfig)), appPackage); const authUser = instanceApis.authApi.getNewUser(); diff --git a/packages/server/appPackages/testApp/appDefinition.json b/packages/server/appPackages/testApp/appDefinition.json index 582ff5b39..6747e91e3 100644 --- a/packages/server/appPackages/testApp/appDefinition.json +++ b/packages/server/appPackages/testApp/appDefinition.json @@ -325,10 +325,10 @@ { "name": "user_name_lookup", "type": "index", - "map": "return {name:record.name, instanceDatastoreConfig:instance.datastoreconfig};", + "map": "return {name:record.unique_name, instanceDatastoreConfig:instance.datastoreconfig};", "filter": "", "indexType": "ancestor", - "getShardName": "return record.name.substring(0,2)", + "getShardName": "return record.unique_name.substring(0,2)", "getSortKey": "record.id", "aggregateGroups": [], "allowedRecordNodeIds": [ @@ -438,7 +438,7 @@ { "actionName": "output_to_file", "eventName": "authApi:createUser:onComplete", - "optionsCreator": "return { filename: filename:'tempaccess' + context.user.name, content:context.result.tempCode };", + "optionsCreator": "return { filename:'tempaccess' + context.user.name, content:context.result.tempCode };", "condition": "" } ] diff --git a/packages/server/appPackages/testApp/dist/package.tar.gz b/packages/server/appPackages/testApp/dist/package.tar.gz index 35f3f0edf..bd99d0227 100644 Binary files a/packages/server/appPackages/testApp/dist/package.tar.gz and b/packages/server/appPackages/testApp/dist/package.tar.gz differ diff --git a/packages/server/middleware/routers.js b/packages/server/middleware/routers.js index 7d378bd11..8498203dc 100644 --- a/packages/server/middleware/routers.js +++ b/packages/server/middleware/routers.js @@ -165,6 +165,21 @@ module.exports = (config, app) => { ); ctx.response.status = StatusCodes.OK; }) + .get("/:appname/api/lookup_field/*", async (ctx) => { + const recordKey = getRecordKey(ctx.params.appname, ctx.request.path) + const fields = ctx.query.fields.split(",") + const recordContext = await ctx.instance.recordApi.getContext( + recordKey + ); + const allContext = []; + for(let field of fields) { + allContext.push( + await recordContext.referenceOptions(field) + ); + } + ctx.body = allContext; + ctx.response.status = StatusCodes.OK; + }) .get("/:appname/api/record/*", async (ctx) => { ctx.body = await ctx.instance.recordApi.load( getRecordKey(ctx.params.appname, ctx.request.path) @@ -198,8 +213,9 @@ module.exports = (config, app) => { const getRecordKey = (appname, wholePath) => wholePath - .replace(`/${appname}/api/record/`, "") - .replace(`/${appname}/api/files/`, ""); + .replace(`/${appname}/api/files/`, "") + .replace(`/${appname}/api/lookup_field/`, "") + .replace(`/${appname}/api/record/`, ""); return router; } diff --git a/packages/server/runtime_apps/testApp/3-dYHF49T8Oyo/access_levels.json b/packages/server/runtime_apps/testApp/3-7HHy_x966Th/access_levels.json similarity index 100% rename from packages/server/runtime_apps/testApp/3-dYHF49T8Oyo/access_levels.json rename to packages/server/runtime_apps/testApp/3-7HHy_x966Th/access_levels.json diff --git a/packages/server/runtime_apps/testApp/3-7HHy_x966Th/appDefinition.json b/packages/server/runtime_apps/testApp/3-7HHy_x966Th/appDefinition.json new file mode 100644 index 000000000..6747e91e3 --- /dev/null +++ b/packages/server/runtime_apps/testApp/3-7HHy_x966Th/appDefinition.json @@ -0,0 +1,445 @@ +{ + "hierarchy": { + "name": "root", + "type": "root", + "children": [ + { + "name": "application", + "type": "record", + "fields": [ + { + "name": "name", + "type": "string", + "typeOptions": { + "maxLength": 500, + "values": null, + "allowDeclaredValuesOnly": false + }, + "label": "Name", + "getInitialValue": "default", + "getUndefinedValue": "default" + }, + { + "name": "domain", + "type": "string", + "typeOptions": { + "maxLength": 500, + "values": null, + "allowDeclaredValuesOnly": false + }, + "label": "domain", + "getInitialValue": "default", + "getUndefinedValue": "default" + }, + { + "name": "application_resolve_strategy", + "type": "string", + "typeOptions": { + "maxLength": 100, + "values": [ + "domain", + "path" + ], + "allowDeclaredValuesOnly": true + }, + "label": "Resolve Application By", + "getInitialValue": "default", + "getUndefinedValue": "default" + } + ], + "children": [ + { + "name": "user", + "type": "record", + "fields": [ + { + "name": "unique_name", + "type": "string", + "typeOptions": { + "maxLength": 200, + "values": null, + "allowDeclaredValuesOnly": false + }, + "label": "Name (unique)", + "getInitialValue": "default", + "getUndefinedValue": "default" + }, + { + "name": "active", + "type": "bool", + "typeOptions": { + "allowNulls": false + }, + "label": "Is Active", + "getInitialValue": "default", + "getUndefinedValue": "default" + }, + { + "name": "instance", + "type": "reference", + "typeOptions": { + "indexNodeKey": "/applications/1-{id}/allinstances", + "reverseIndexNodeKeys": [ + "/applications/1-{id}/instances/2-{id}/users_on_this_instance" + ], + "displayValue": "name" + }, + "label": "Instance", + "getInitialValue": "default", + "getUndefinedValue": "default" + } + ], + "children": [], + "validationRules": [], + "nodeId": 8, + "indexes": [], + "allidsShardFactor": "64", + "collectionName": "users", + "isSingle": false + }, + { + "name": "instance", + "type": "record", + "fields": [ + { + "name": "name", + "type": "string", + "typeOptions": { + "maxLength": 1000, + "values": null, + "allowDeclaredValuesOnly": false + }, + "label": "Name", + "getInitialValue": "default", + "getUndefinedValue": "default" + }, + { + "name": "active", + "type": "bool", + "typeOptions": { + "allowNulls": false + }, + "label": "Is Active", + "getInitialValue": "default", + "getUndefinedValue": "default" + }, + { + "name": "version", + "type": "reference", + "typeOptions": { + "indexNodeKey": "/applications/1-{id}/all_versions", + "reverseIndexNodeKeys": [ + "/applications/1-{id}/versions/3-{id}/instances_on_this_version" + ], + "displayValue": "name" + }, + "label": "Version", + "getInitialValue": "default", + "getUndefinedValue": "default" + }, + { + "name": "datastoreconfig", + "type": "string", + "typeOptions": { + "maxLength": 1000, + "values": null, + "allowDeclaredValuesOnly": false + }, + "label": "Datastore Config", + "getInitialValue": "default", + "getUndefinedValue": "default" + } + ], + "children": [], + "validationRules": [], + "nodeId": 2, + "indexes": [ + { + "name": "users_on_this_instance", + "type": "index", + "map": "return {...record};", + "filter": "", + "indexType": "reference", + "getShardName": "", + "getSortKey": "record.id", + "aggregateGroups": [], + "allowedRecordNodeIds": [], + "nodeId": 15 + } + ], + "allidsShardFactor": 1, + "collectionName": "instances", + "isSingle": false + }, + { + "name": "version", + "type": "record", + "fields": [ + { + "name": "name", + "type": "string", + "typeOptions": { + "maxLength": 200, + "values": null, + "allowDeclaredValuesOnly": false + }, + "label": "Name", + "getInitialValue": "default", + "getUndefinedValue": "default" + }, + { + "name": "package", + "type": "file", + "typeOptions": {}, + "label": "Package", + "getInitialValue": "default", + "getUndefinedValue": "default" + } + ], + "children": [], + "validationRules": [], + "nodeId": 3, + "indexes": [ + { + "name": "instances_for_this_version", + "type": "index", + "map": "return {name:record.name};", + "filter": "", + "indexType": "ancestor", + "getShardName": "", + "getSortKey": "record.id", + "aggregateGroups": [], + "allowedRecordNodeIds": [], + "nodeId": 9 + }, + { + "name": "instances_on_this_version", + "type": "index", + "map": "return {...record};", + "filter": "", + "indexType": "reference", + "getShardName": "", + "getSortKey": "record.id", + "aggregateGroups": [], + "allowedRecordNodeIds": [], + "nodeId": 10 + } + ], + "allidsShardFactor": 1, + "collectionName": "versions", + "isSingle": false + }, + { + "name": "session", + "type": "record", + "fields": [ + { + "name": "created", + "type": "number", + "typeOptions": { + "minValue": 0, + "maxValue": 99999999999999, + "decimalPlaces": 0 + }, + "label": "Created", + "getInitialValue": "default", + "getUndefinedValue": "default" + }, + { + "name": "user_json", + "type": "string", + "typeOptions": { + "maxLength": null, + "values": null, + "allowDeclaredValuesOnly": false + }, + "label": "User Json", + "getInitialValue": "default", + "getUndefinedValue": "default" + }, + { + "name": "instanceDatastoreConfig", + "type": "string", + "typeOptions": { + "maxLength": null, + "values": null, + "allowDeclaredValuesOnly": false + }, + "label": "Instance Datastore Config", + "getInitialValue": "default", + "getUndefinedValue": "default" + }, + { + "name": "username", + "type": "string", + "typeOptions": { + "maxLength": null, + "values": null, + "allowDeclaredValuesOnly": false + }, + "label": "User", + "getInitialValue": "default", + "getUndefinedValue": "default" + } + ], + "children": [], + "validationRules": [], + "nodeId": 16, + "indexes": [], + "allidsShardFactor": 1, + "collectionName": "sessions", + "isSingle": false + } + ], + "validationRules": [], + "nodeId": 1, + "indexes": [ + { + "name": "allinstances", + "type": "index", + "map": "return {...record};", + "filter": "", + "indexType": "ancestor", + "getShardName": "", + "getSortKey": "record.id", + "aggregateGroups": [], + "allowedRecordNodeIds": [ + 2 + ], + "nodeId": 23 + }, + { + "name": "sessions_by_user", + "type": "index", + "map": "return {username:record.username};", + "filter": "", + "indexType": "ancestor", + "getShardName": "return record.username.substring(0,2)", + "getSortKey": "record.id", + "aggregateGroups": [], + "allowedRecordNodeIds": [ + 16 + ], + "nodeId": 24 + }, + { + "name": "user_name_lookup", + "type": "index", + "map": "return {name:record.unique_name, instanceDatastoreConfig:instance.datastoreconfig};", + "filter": "", + "indexType": "ancestor", + "getShardName": "return record.unique_name.substring(0,2)", + "getSortKey": "record.id", + "aggregateGroups": [], + "allowedRecordNodeIds": [ + 8 + ], + "nodeId": 25 + }, + { + "name": "all_versions", + "type": "index", + "map": "return {...record};", + "filter": "", + "indexType": "ancestor", + "getShardName": "", + "getSortKey": "record.id", + "aggregateGroups": [], + "allowedRecordNodeIds": [ + 3 + ], + "nodeId": 26 + } + ], + "allidsShardFactor": 64, + "collectionName": "applications", + "isSingle": false + }, + { + "name": "mastersession", + "type": "record", + "fields": [ + { + "name": "user_json", + "type": "string", + "typeOptions": { + "maxLength": 10000, + "values": null, + "allowDeclaredValuesOnly": false + }, + "label": "User Json", + "getInitialValue": "default", + "getUndefinedValue": "default" + }, + { + "name": "username", + "type": "string", + "typeOptions": { + "maxLength": null, + "values": null, + "allowDeclaredValuesOnly": false + }, + "label": "User", + "getInitialValue": "default", + "getUndefinedValue": "default" + } + ], + "children": [], + "validationRules": [], + "nodeId": 17, + "indexes": [], + "allidsShardFactor": 64, + "collectionName": "sessions", + "isSingle": false + } + ], + "pathMaps": [], + "indexes": [ + { + "name": "all_applications", + "type": "index", + "map": "return {...record};", + "filter": "", + "indexType": "ancestor", + "getShardName": "", + "getSortKey": "record.id", + "aggregateGroups": [], + "allowedRecordNodeIds": [ + 1 + ], + "nodeId": 22 + }, + { + "name": "mastersessions_by_user", + "type": "index", + "map": "return {username:record.username};", + "filter": "", + "indexType": "ancestor", + "getShardName": "return record.username.substring(0,2)", + "getSortKey": "record.id", + "aggregateGroups": [], + "allowedRecordNodeIds": [ + 17 + ], + "nodeId": 27 + } + ], + "nodeId": 0 + }, + "actions": { + "output_to_file": { + "name": "output_to_file", + "behaviourSource": "main", + "behaviourName": "outputToFile", + "initialOptions": {} + } + }, + "triggers": [ + { + "actionName": "output_to_file", + "eventName": "authApi:createUser:onComplete", + "optionsCreator": "return { filename:'tempaccess' + context.user.name, content:context.result.tempCode };", + "condition": "" + } + ] +} \ No newline at end of file diff --git a/packages/server/runtime_apps/testApp/3-7HHy_x966Th/plugins.js b/packages/server/runtime_apps/testApp/3-7HHy_x966Th/plugins.js new file mode 100644 index 000000000..838a10a7f --- /dev/null +++ b/packages/server/runtime_apps/testApp/3-7HHy_x966Th/plugins.js @@ -0,0 +1,9 @@ +const fs = require("fs"); + +module.exports = (config) => ({ + main: { + outputToFile : ({filename, content}) => { + fs.writeFile(`./tests/.data/${filename}`, content, {encoding:"utf8"}); + } + } +}) \ No newline at end of file diff --git a/packages/server/runtime_apps/testApp/3-dYHF49T8Oyo/appDefinition.json b/packages/server/runtime_apps/testApp/3-dYHF49T8Oyo/appDefinition.json deleted file mode 100644 index 61f0510f5..000000000 --- a/packages/server/runtime_apps/testApp/3-dYHF49T8Oyo/appDefinition.json +++ /dev/null @@ -1 +0,0 @@ -{"hierarchy":{"name":"root","type":"root","children":[{"name":"application","type":"record","fields":[{"name":"name","type":"string","typeOptions":{"maxLength":500,"values":null,"allowDeclaredValuesOnly":false},"label":"Name","getInitialValue":"default","getUndefinedValue":"default"},{"name":"domain","type":"string","typeOptions":{"maxLength":500,"values":null,"allowDeclaredValuesOnly":false},"label":"domain","getInitialValue":"default","getUndefinedValue":"default"},{"name":"application_resolve_strategy","type":"string","typeOptions":{"maxLength":100,"values":["domain","path"],"allowDeclaredValuesOnly":true},"label":"Resolve Application By","getInitialValue":"default","getUndefinedValue":"default"}],"children":[{"name":"user","type":"record","fields":[{"name":"unique_name","type":"string","typeOptions":{"maxLength":200,"values":null,"allowDeclaredValuesOnly":false},"label":"Name (unique)","getInitialValue":"default","getUndefinedValue":"default"},{"name":"active","type":"bool","typeOptions":{"allowNulls":false},"label":"Is Active","getInitialValue":"default","getUndefinedValue":"default"},{"name":"instance","type":"reference","typeOptions":{"indexNodeKey":"/applications/1-{id}/allinstances","reverseIndexNodeKeys":["/applications/1-{id}/instances/2-{id}/users_on_this_instance"],"displayValue":"name"},"label":"Instance","getInitialValue":"default","getUndefinedValue":"default"}],"children":[],"validationRules":[],"nodeId":8,"indexes":[],"allidsShardFactor":"64","collectionName":"users","isSingle":false},{"name":"instance","type":"record","fields":[{"name":"name","type":"string","typeOptions":{"maxLength":1000,"values":null,"allowDeclaredValuesOnly":false},"label":"Name","getInitialValue":"default","getUndefinedValue":"default"},{"name":"active","type":"bool","typeOptions":{"allowNulls":false},"label":"Is Active","getInitialValue":"default","getUndefinedValue":"default"},{"name":"version","type":"reference","typeOptions":{"indexNodeKey":"/applications/1-{id}/all_versions","reverseIndexNodeKeys":["/applications/1-{id}/versions/3-{id}/instances_on_this_version"],"displayValue":"name"},"label":"Version","getInitialValue":"default","getUndefinedValue":"default"},{"name":"datastoreconfig","type":"string","typeOptions":{"maxLength":1000,"values":null,"allowDeclaredValuesOnly":false},"label":"Datastore Config","getInitialValue":"default","getUndefinedValue":"default"}],"children":[],"validationRules":[],"nodeId":2,"indexes":[{"name":"users_on_this_instance","type":"index","map":"return {...record};","filter":"","indexType":"reference","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[],"nodeId":15}],"allidsShardFactor":1,"collectionName":"instances","isSingle":false},{"name":"version","type":"record","fields":[{"name":"name","type":"string","typeOptions":{"maxLength":200,"values":null,"allowDeclaredValuesOnly":false},"label":"Name","getInitialValue":"default","getUndefinedValue":"default"},{"name":"package","type":"file","typeOptions":{},"label":"Package","getInitialValue":"default","getUndefinedValue":"default"}],"children":[],"validationRules":[],"nodeId":3,"indexes":[{"name":"instances_for_this_version","type":"index","map":"return {name:record.name};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[],"nodeId":9},{"name":"instances_on_this_version","type":"index","map":"return {...record};","filter":"","indexType":"reference","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[],"nodeId":10}],"allidsShardFactor":1,"collectionName":"versions","isSingle":false},{"name":"session","type":"record","fields":[{"name":"created","type":"number","typeOptions":{"minValue":0,"maxValue":99999999999999,"decimalPlaces":0},"label":"Created","getInitialValue":"default","getUndefinedValue":"default"},{"name":"user_json","type":"string","typeOptions":{"maxLength":null,"values":null,"allowDeclaredValuesOnly":false},"label":"User Json","getInitialValue":"default","getUndefinedValue":"default"},{"name":"instanceDatastoreConfig","type":"string","typeOptions":{"maxLength":null,"values":null,"allowDeclaredValuesOnly":false},"label":"Instance Datastore Config","getInitialValue":"default","getUndefinedValue":"default"},{"name":"username","type":"string","typeOptions":{"maxLength":null,"values":null,"allowDeclaredValuesOnly":false},"label":"User","getInitialValue":"default","getUndefinedValue":"default"}],"children":[],"validationRules":[],"nodeId":16,"indexes":[],"allidsShardFactor":1,"collectionName":"sessions","isSingle":false}],"validationRules":[],"nodeId":1,"indexes":[{"name":"allinstances","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[2],"nodeId":23},{"name":"sessions_by_user","type":"index","map":"return {username:record.username};","filter":"","indexType":"ancestor","getShardName":"return record.username.substring(0,2)","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[16],"nodeId":24},{"name":"user_name_lookup","type":"index","map":"return {name:record.name, instanceDatastoreConfig:instance.datastoreconfig};","filter":"","indexType":"ancestor","getShardName":"return record.name.substring(0,2)","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[8],"nodeId":25},{"name":"all_versions","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[3],"nodeId":26}],"allidsShardFactor":64,"collectionName":"applications","isSingle":false},{"name":"mastersession","type":"record","fields":[{"name":"user_json","type":"string","typeOptions":{"maxLength":10000,"values":null,"allowDeclaredValuesOnly":false},"label":"User Json","getInitialValue":"default","getUndefinedValue":"default"},{"name":"username","type":"string","typeOptions":{"maxLength":null,"values":null,"allowDeclaredValuesOnly":false},"label":"User","getInitialValue":"default","getUndefinedValue":"default"}],"children":[],"validationRules":[],"nodeId":17,"indexes":[],"allidsShardFactor":64,"collectionName":"sessions","isSingle":false}],"pathMaps":[],"indexes":[{"name":"all_applications","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[1],"nodeId":22},{"name":"mastersessions_by_user","type":"index","map":"return {username:record.username};","filter":"","indexType":"ancestor","getShardName":"return record.username.substring(0,2)","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[17],"nodeId":27}],"nodeId":0},"actions":{},"triggers":[]} \ No newline at end of file diff --git a/packages/server/tests/createNewApp.js b/packages/server/tests/createNewApp.js index 48fb98bb1..e29630127 100644 --- a/packages/server/tests/createNewApp.js +++ b/packages/server/tests/createNewApp.js @@ -6,6 +6,7 @@ const masterAppDefinition = constructHierarchy( require("../appPackages/master/appDefinition.json")); const {getApisWithFullAccess} = require("../utilities/budibaseApi"); const { createTarGzPackage } = require("../utilities/targzAppPackage"); +const { timeout } = require("./helpers"); module.exports = (app) => { @@ -40,6 +41,7 @@ module.exports = (app) => { const version1 = master.recordApi .getNew(`${newAppKey}/versions`, "version"); version1.name = "v1"; + version1.defaultAccessLevel = "owner"; version1Key = version1.key; const { path, size } = await createTarGzPackage(app.config, "testApp"); @@ -57,26 +59,62 @@ module.exports = (app) => { }); - let instance1Key; + let instance1; it("should be able to create new instance of app", async () => { const master = await getmaster(); - const instance1 = master.recordApi + instance1 = master.recordApi .getNew(`${newAppKey}/instances`, "instance"); instance1.name = "instance 1"; instance1.active = true; instance1.version = {key:version1Key, name:"v1", defaultAccessLevel:"owner"}; - instance1Key = instance1.key; await app.post(`/_master/api/record/${instance1.key}`, instance1) .set("cookie", app.masterAuth.cookie) .expect(statusCodes.OK); + const loadInstanceResponse = await app.get(`/_master/api/record/${instance1.key}`) + .set("cookie", app.masterAuth.cookie) + .expect(statusCodes.OK); + + instance1 = loadInstanceResponse.body; + }); - it("should be able to create new user on instance", async () => { + let user1_instance1; + it("should be able to create new user on instance, via master", async () => { + const master = await getmaster(); + user1_instance1 = master.recordApi + .getNew(`${newAppKey}/users`, "user"); + user1_instance1.name = "testAppUser1"; - + /*const lookupResponse = await app.get(`/_master/api/lookup_field/${user1_instance1.key}?fields=instance`) + .set("cookie", app.masterAuth.cookie) + .expect(statusCodes.OK); + */ + user1_instance1.instance = instance1; + user1_instance1.active = true; + //await timeout(100); + await app.post(`/_master/api/record/${user1_instance1.key}`, user1_instance1) + .set("cookie", app.masterAuth.cookie) + .expect(statusCodes.OK); }); + it("should be able to set password for new user using temporary code", async () => { + const testUserTempCode = await readFile(`./tests/.data/tempaccess${user1_instance1.name}`, "utf8"); + user1_instance1.password = "user1_instance1_password"; + + await app.post("/testApp/api/setPasswordFromTemporaryCode", { + username: user1_instance1.name, + tempCode:testUserTempCode, + newPassword:user1_instance1.password + }) + .expect(statusCodes.OK); + + await app.post("/testApp/api/authenticate", { + username: user1_instance1.name, + password: user1_instance1.password + }) + .expect(statusCodes.OK); + }) } \ No newline at end of file diff --git a/packages/server/utilities/createAppPackage.js b/packages/server/utilities/createAppPackage.js index 8224588cd..bb0a5c304 100644 --- a/packages/server/utilities/createAppPackage.js +++ b/packages/server/utilities/createAppPackage.js @@ -1,14 +1,24 @@ const { join } = require("path"); const constructHierarchy = require("./constructHierarchy"); const { common } = require("budibase-core"); -const createAppPackage = (appPath) => ({ - appDefinition: require(join(appPath, "appDefinition.json")), - behaviourSources: require(join(appPath, "plugins.js")), - appPath -}); +const { getRuntimePackageDirectory } = require("../utilities/runtimePackages"); +const createAppPackage = (config, appPath) => { + + const appDefModule = require( + join(appPath, "appDefinition.json")); + + const pluginsModule = require( + join(appPath, "plugins.js")); + + return ({ + appDefinition: appDefModule, + behaviourSources: pluginsModule(config), + appPath + }) +} module.exports.masterAppPackage = (config) => { - const standardPackage = createAppPackage("../appPackages/master"); + const standardPackage = createAppPackage(config, "../appPackages/master"); const customizeMaster = config && config.customizeMaster ? config.customizeMaster @@ -31,8 +41,11 @@ module.exports.masterAppPackage = (config) => { }); } -module.exports.applictionVersionPackage = (appname, versionId) => { - const pkg = createAppPackage(`../runtimePackages/${appname}/${versionId}`); - pkg.appDefinition = constructHierarchy(appDefinition); +module.exports.applictionVersionPackage = (config, appname, versionId) => { + const pkg = createAppPackage( + config, + join("..", getRuntimePackageDirectory(appname, versionId)) + ); + pkg.appDefinition = constructHierarchy(pkg.appDefinition); return pkg; } diff --git a/packages/server/utilities/masterAppInternal.js b/packages/server/utilities/masterAppInternal.js index dfdb9ace7..74e3e42b4 100644 --- a/packages/server/utilities/masterAppInternal.js +++ b/packages/server/utilities/masterAppInternal.js @@ -88,22 +88,20 @@ module.exports = async (config) => { const app = await getApplication(appname); - const userInMaster = await bb.indexApi.listItems( - `/applications/${app.id}/users_by_name`, - {name:username} - ).find(u => u.name === username); + const userInMaster = await getUser(bb, app.id, username); const instance = await bb.recordApi.load( - userInMaster.instance.key); + userInMaster.instanceKey); const versionId = $(instance.version.key, [ splitKey, last ]); + const dsConfig = JSON.parse(instance.datastoreconfig); const bbInstance = await getApisWithFullAccess( - datastoreModule.getDatastore(instance.datastoreconfig), - applictionVersionPackage(appname, versionId) + datastoreModule.getDatastore(dsConfig), + applictionVersionPackage(config, appname, versionId) ); const authUser = await bbInstance.authApi.authenticate(username, password); @@ -140,10 +138,11 @@ module.exports = async (config) => { const customId = bb.recordApi.customId("session", sessionId); try { const session = await bb.recordApi.load(`/applications/${app.id}/sessions/${customId}`); - const instanceDatastore = getInstanceDatastore(session.instanceDatastoreConfig) + const dsConfig = JSON.parse(session.instanceDatastoreConfig); + const instanceDatastore = getInstanceDatastore(dsConfig) return await getApisForSession( instanceDatastore, - applictionVersionPackage(appname, session.instanceVersion), + applictionVersionPackage(config, appname, session.instanceVersion), session); } catch(_) { return null; @@ -151,6 +150,19 @@ module.exports = async (config) => { } }; + const getUser = async (bb, appId, username ) => { + const matches = await bb.indexApi.listItems( + `/applications/${appId}/user_name_lookup`, + { + rangeStartParams:{name:username}, + rangeEndParams:{name:username}, + searchPhrase:`name:${username}` + } + ); + if(matches.length !== 1) return; + return matches[0]; + } + const getFullAccessInstanceApiForUsername = async (appname, username) => { if(isMaster(appname)) { @@ -158,20 +170,21 @@ module.exports = async (config) => { } else { const app = await getApplication(appname); - const matches = bb.indexApi.listItems( - `/applications/${app.id}/user_name_lookup`, - { - rangeStartParams:{name:username}, - rangeEndParams:{name:username}, - searchPhrase:`name:${username}` - } - ); - if(matches.length !== 1) return; + const user = await getUser(bb, app.id, username); + const dsConfig = JSON.parse(user.instanceDatastoreConfig); const instanceDatastore = getInstanceDatastore( - matches[0].instanceDatastoreConfig); - - return await getApisWithFullAccess(instanceDatastore); + dsConfig + ); + + const versionId = $((await bb.recordApi.load(user.instanceKey)).version.key, [ + splitKey, + last + ]); + + return await getApisWithFullAccess( + instanceDatastore, + applictionVersionPackage(config, appname, versionId)); } };