From 921b31d5954b56d27997edd8d6ad55938e189e11 Mon Sep 17 00:00:00 2001 From: michael shanks Date: Tue, 16 Jul 2019 22:14:57 +0100 Subject: [PATCH] refactoring routes to serve app UIs --- .gitignore | 1 + et 04eef6ab4d291621114949c14097987ec1804274q | 35 ------------ lerna.json | 1 + .../appPackages/master/appDefinition.json | 26 +++++++++ .../appPackages/testApp/dist/package.tar.gz | Bin 1211 -> 1053 bytes packages/server/middleware/routers.js | 54 ++++++++++++------ packages/server/package.json | 6 +- packages/server/utilities/createAppPackage.js | 30 ++++++++-- .../server/utilities/masterAppInternal.js | 43 ++++++++++---- 9 files changed, 124 insertions(+), 72 deletions(-) delete mode 100644 et 04eef6ab4d291621114949c14097987ec1804274q diff --git a/.gitignore b/.gitignore index 4e653a6479..d497b6eab9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .data/ .temp/ +packages/server/runtime_apps/ # Logs logs diff --git a/et 04eef6ab4d291621114949c14097987ec1804274q b/et 04eef6ab4d291621114949c14097987ec1804274q deleted file mode 100644 index 0359714f20..0000000000 --- a/et 04eef6ab4d291621114949c14097987ec1804274q +++ /dev/null @@ -1,35 +0,0 @@ -commit 78a241d11c55ae717ba844c3d853e594d805e0a2 (HEAD -> master) -Author: michael shanks -Date: Fri Jun 7 14:11:23 2019 +0100 - - mono-repo - -commit 04eef6ab4d291621114949c14097987ec1804274 (bb/master) -Author: michael shanks -Date: Fri Jun 7 12:22:23 2019 +0100 - - license AGPL - -commit 5bcf5157e0010aea34be4bc338057a75ae0befec -Author: michael shanks -Date: Fri Jun 7 12:09:06 2019 +0100 - - making OS friendly :) - -commit d5129fbda3c0fbb35e7275420aee0b2e8a4f6c2b -Author: michael shanks -Date: Fri Jun 7 12:02:48 2019 +0100 - - initialise master database working - -commit 36f9e7c64faf9c1ce27a1586337b4bd168fe88ec (origin/master, origin/HEAD) -Author: Michael Shanks -Date: Fri Apr 5 16:30:29 2019 +0100 - - backup.. - -commit a8aa18d01d0640db6fb0f7bcb20e713b38b5610b -Author: Michael Shanks -Date: Tue Mar 19 21:45:21 2019 +0000 - - initial commit diff --git a/lerna.json b/lerna.json index d6707ca0cd..cd82d7703d 100644 --- a/lerna.json +++ b/lerna.json @@ -1,4 +1,5 @@ { + "npmClient": "npm", "packages": [ "packages/*" ], diff --git a/packages/server/appPackages/master/appDefinition.json b/packages/server/appPackages/master/appDefinition.json index 244e9f87ef..e9399f759a 100644 --- a/packages/server/appPackages/master/appDefinition.json +++ b/packages/server/appPackages/master/appDefinition.json @@ -45,6 +45,20 @@ "label": "Resolve Application By", "getInitialValue": "default", "getUndefinedValue": "default" + }, + { + "name": "defaultVersion", + "type": "reference", + "typeOptions": { + "indexNodeKey": "/applications/1-{id}/all_versions", + "reverseIndexNodeKeys": [ + "/applications/1-{id}/versions/3-{id}/isdefault" + ], + "displayValue": "name" + }, + "label": "Default Version", + "getInitialValue": "default", + "getUndefinedValue": "default" } ], "children": [ @@ -237,6 +251,18 @@ "aggregateGroups": [], "allowedRecordNodeIds": [], "nodeId": 10 + }, + { + "name": "isdefault", + "type": "index", + "map": "return {};", + "filter": "", + "indexType": "reference", + "getShardName": "", + "getSortKey": "record.id", + "aggregateGroups": [], + "allowedRecordNodeIds": [], + "nodeId": 28 } ], "allidsShardFactor": 1, diff --git a/packages/server/appPackages/testApp/dist/package.tar.gz b/packages/server/appPackages/testApp/dist/package.tar.gz index 26e2b97a8d553cfa4a184a229d4e3cb45accec75..8cd74900b66488d09325bde70dea1c63d4b0b69f 100644 GIT binary patch literal 1053 zcmV+&1mgQ2iwFP!000003hfwcZ`(F7p9ADSu)=^QsAfx+?Q|+Sph!`m*wz+HyDvqM zGSbQBK$99t!DRlb+cqH+Hdph*H+A9FYbt~>u~Dehjzn)ru<{?Nuh z?BPokMI;D&mw%rksG%-SF2bOG~fxn{6p@xW%?2Pj4d)bxd!(=?0c{nK+dU zYp2`$9+j_Ra|4H6#pc?cxQfY{VyKFNNzTzUy~1gQ#++#_YcM3ITAx|D%jA}oR8(CM z*MZt3Am|APA{9xQu3i_JJ9XSnGE3kVnlo*xJd_EtqnH@YzTfA@jhQKy)A^qu zMrQ2AA$k()i1GqkPAm$}eUEZ3&t5~qse<&M3iV!aR6e6zL+N{*o&dj;HUjh3W;f*( zan)BdT5#iVpRnFB{b#INSX;rXES@#V3n}HbjHVM=h?X-&F*#}c)i#@nnF_yMf^WUC zYB`03O(_4sX<}W|YuVihyd%qxst7O~X{hSo1-J6-qMamfQV#XUA)WwwoBRJm zK+cO16ZYnRe=^p^KXUi~>i?g?u#fQ%dlmitsdNcHdHk_!;;ksto$ZNCar$=P9J{))B)dqSvC$rR`8(O2?rakT+a6;w`>@b%j3h?7y1zI5yQ~V9W{{xPoz&C?%P;dn~myCbeRkxnE39uYaE zN>RZJ+e%w4n!btb_COM>36dlbGF*~LS%{GQPHqfZD*$(hDUqt>{XC~(;w&+f#$8N8 z!pP2<#8J3=O~6{=j#+H#krw4ML7`~0{HHVCR!lbyi>;V$=E1F4UP%gSYBG%&7+Gx+ z4Y7hGf5<*XG>WiNS4Phb7#eAX#PSBEjp#u%2*;O~WYr*!Q6&>CC`J277?qqr>F6 z+uj})fTQRg8BtD+E1zfn>vY;}JO6pzZpUx?cK-9d{rvY7kj{S-N}vb_6VsIzX`fGi zQV5;3uw{EIehem*g_7{%AXq3KIi;-I6&qrqVOD#kGoplrmGQDtmI~DEZ=#*KXGQv zJi<(oGJaAOkKs$g*6KDU`h&?^%q-z_)EVKJ={nRe&@3R&7g7|Fi@3@1Wmt4Yor?{u zbH-whS?iCw$!M*|YZ#T7;i-uEiqa*1Jf2>b1FwW~OAJ_?Ddm~jeqBNhwKQh#jT@4H zPBHtF;lKuwzlv223cD{4j9XN{e|Ti*_X`m#RQbcO>c?WZtSmyxP&fvF!T*YxReKf3 z49OotW0C5L9eUR6f^4IqI-g(}zQ=(U(xmN*Z29DJRt{FR5{^`zL)BoUE?w7U${pG* zH7g3XPODmtdYw{cuBekADoVw4oh}PKGOkX9_2eUtN}|+>w^YP6AJQ;&a8OAkN5ndc z^@SD}BWk(V+%1$*mX{2dWP)c@#PS^eg2nhrc^$@CiPmTFzD$XxnNY~{q%fi`gohq6 z9vi#W+=JkfiPuUD^EB5P7LN7gZA1s@S?3GP-2=f-1)R^|JX+W!QmIZ2n)NW0M;%L! z=E#sYW*WRQC#7_1e}#U6@tbRMt(#_;ZyJO~`ibj7wj_yy)NPu5r{F4-ye_Z=q|lCh zhT9L>mdZ&kD?N{Ch0oc6@2%BkCk8pY#U8hq!6`(<@THtl;N+}#&EuZ;|DNyn;Q-*m z{O@|6zrX)~3W!)drrg~8?~cb^{%?1B`Tu{qy$&+oxA?mgX$ddf|4;#yMk9sZAW6Q( zRFY$7q@0u2M~6p;QxU=p( { + +} module.exports = (config, app) => { @@ -23,6 +26,22 @@ module.exports = (config, app) => { .use(async (ctx, next) => { ctx.sessionId = ctx.session._sessCtx.externalKey; ctx.session.accessed = true; + + const pathParts = ctx.path.split("/"); + + if(pathParts.length < 2) { + ctx.throw(StatusCodes.NOT_FOUND, "App Name not declared"); + } + + const instance = await ctx.master.getInstanceApiForSession( + pathParts[1], + ctx.sessionId); + + + ctx.instance = instance.instance; + ctx.publicPath = instance.publicPath; + ctx.isAuthenticated = !!instance.instance; + await next(); }) .get("/_builder", async (ctx) => { @@ -46,11 +65,9 @@ module.exports = (config, app) => { if(path.startsWith("/api/")) { await next(); - return; + } else { + await send(ctx, path, { root: builderPath }); } - - await send(ctx, path, { root: builderPath }); - }) .get("/:appname", async (ctx) => { ctx.response.status = StatusCodes.OK; @@ -139,22 +156,23 @@ module.exports = (config, app) => { ctx.request.body); ctx.response.status = StatusCodes.OK; }) - .use(async (ctx, next) => { + .get("/:appname", async (ctx) => { + await send(ctx, "/index.html", { root: ctx.publicPath }); + }) + .get("/:appname/*", async (ctx, next) => { + const path = ctx.path.replace(`/${ctx.params.appname}`, ""); - const pathParts = ctx.path.split("/"); - - if(pathParts.length < 2) { - ctx.throw(StatusCodes.NOT_FOUND, "App Name not declared"); - } - - ctx.instance = await ctx.master.getInstanceApiForSession( - pathParts[1], - ctx.sessionId); - - if(ctx.instance === null) { - ctx.response.status = StatusCodes.UNAUTHORIZED; - } else { + if(path.startsWith("/api/")) { await next(); + } else { + await send(ctx, path, { root: ctx.publicPath }); + } + }) + .use(async (ctx, next) => { + if(ctx.isAuthenticated) { + await next(); + } else { + ctx.response.status = StatusCodes.UNAUTHORIZED; } }) .post("/:appname/api/changeMyPassword", async (ctx) => { diff --git a/packages/server/package.json b/packages/server/package.json index f09a464618..834c3f0779 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "budibase", "version": "0.0.1", - "description": "budibase wrapper repo for development", + "description": "Budibase Web Server", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" @@ -18,6 +18,8 @@ "koa": "^2.7.0", "koa-body": "^4.1.0", "koa-session": "^5.12.0", + "koa-send": "^5.0.0", + "koa-static": "^5.0.0", "ncp": "^2.0.0", "rimraf": "^2.6.3", "tar-fs": "^2.0.0", @@ -27,8 +29,6 @@ "devDependencies": { "@jest/test-sequencer": "^24.8.0", "jest": "^24.8.0", - "koa-send": "^5.0.0", - "koa-static": "^5.0.0", "server-destroy": "^1.0.1", "supertest": "^4.0.2" }, diff --git a/packages/server/utilities/createAppPackage.js b/packages/server/utilities/createAppPackage.js index 4efa10ea69..cdea3d90f0 100644 --- a/packages/server/utilities/createAppPackage.js +++ b/packages/server/utilities/createAppPackage.js @@ -21,8 +21,9 @@ const createAppPackage = (context, appPath) => { appDefinition: appDefModule, behaviourSources: pluginsModule(context), appPath, - accessLevels - }) + accessLevels, + ...publicPaths(appPath) + }); } const appPackageFolder = (config, appname) => @@ -53,15 +54,34 @@ module.exports.masterAppPackage = (context) => { behaviourSources: config && config.extraMasterPlugins ? {...plugins, ...config.extraMasterPlugins} : plugins, - appPath: standardPackage.appPath + appPath: standardPackage.appPath, + unauthenticatedUiPath: standardPackage.unauthenticatedUiPath, + mainUiPath: standardPackage.mainUiPath }); } - + +const applictionVersionPath = (appname, versionId) => + join("..", getRuntimePackageDirectory(appname, versionId)) + +const publicPaths = (appPath) => ({ + mainUiPath: join( + appPath, "ui", "main", "public"), + unauthenticatedUiPath: join( + appPath, "ui", "unauthenticated", "public") + + }); + +module.exports.applictionVersionPublicPaths = (appname, versionId) => { + const appPath = applictionVersionPath(appname, versionId); + return publicPaths(appPath); +} + module.exports.applictionVersionPackage = async (context, appname, versionId, instanceKey) => { const pkg = createAppPackage( context, - join("..", getRuntimePackageDirectory(appname, versionId)) + applictionVersionPath(appname, versionId) ); + pkg.appDefinition = constructHierarchy(pkg.appDefinition); await injectPlugins( pkg, diff --git a/packages/server/utilities/masterAppInternal.js b/packages/server/utilities/masterAppInternal.js index 18f0506a57..c77d632444 100644 --- a/packages/server/utilities/masterAppInternal.js +++ b/packages/server/utilities/masterAppInternal.js @@ -7,7 +7,11 @@ const getDatastore = require("./datastore"); const getDatabaseManager = require("./databaseManager"); const {$, splitKey} = require("budibase-core").common; const { keyBy, last } = require("lodash/fp"); -const { masterAppPackage, applictionVersionPackage } = require("../utilities/createAppPackage"); +const { + masterAppPackage, + applictionVersionPackage, + applictionVersionPublicPaths + } = require("../utilities/createAppPackage"); const isMaster = appname => appname === "_master"; @@ -137,15 +141,23 @@ module.exports = async (context) => { const getInstanceApiForSession = async (appname, sessionId) => { if(isMaster(appname)) { const customId = bb.recordApi.customId("mastersession", sessionId); + const masterPkg = masterAppPackage(context); try { const session = await bb.recordApi.load(`/sessions/${customId}`); - return await getApisForSession( - masterDatastore, - masterAppPackage(context), - session); + return ({ + instance: await getApisForSession( + masterDatastore, + masterAppPackage(context), + session), + publicPath: masterPkg.mainUiPath + }); + } catch(_) { - return null; + return ({ + instance: null, + publicPath: masterPkg.unauthenticatedUiPath + }); } } else { @@ -163,12 +175,21 @@ module.exports = async (context) => { const appPackage = await applictionVersionPackage( context, appname, versionId, session.instanceKey); - return await getApisForSession( - instanceDatastore, - appPackage, - session); + return ({ + instance: await getApisForSession( + instanceDatastore, + appPackage, + session), + publicPath: appPackage.mainUiPath + }); + } catch(_) { - return null; + return ({ + instance:null, + publicPath: applictionVersionPublicPaths( + app.name, + app.defaultVersion.id).unauthenticatedUiPath + }); } } };