Auth working
This commit is contained in:
parent
b6b50182e2
commit
910030e929
|
@ -1,8 +1,11 @@
|
||||||
const apiCall = method => async (url, body) => {
|
const apiCall = method => async (url, body) => {
|
||||||
|
const jwt = localStorage.getItem("budibase:token");
|
||||||
|
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
method: method,
|
method: method,
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": `Bearer ${jwt}`
|
||||||
},
|
},
|
||||||
body: body && JSON.stringify(body),
|
body: body && JSON.stringify(body),
|
||||||
})
|
})
|
||||||
|
|
|
@ -167,7 +167,6 @@ const _saveScreenApi = (screen, s) =>
|
||||||
|
|
||||||
const createScreen = store => (screenName, route, layoutComponentName) => {
|
const createScreen = store => (screenName, route, layoutComponentName) => {
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
console.log(layoutComponentName);
|
|
||||||
const rootComponent = state.components[layoutComponentName]
|
const rootComponent = state.components[layoutComponentName]
|
||||||
|
|
||||||
const newScreen = {
|
const newScreen = {
|
||||||
|
|
|
@ -118,9 +118,6 @@
|
||||||
<i class="ri-more-line" />
|
<i class="ri-more-line" />
|
||||||
<div uk-dropdown="mode: click">
|
<div uk-dropdown="mode: click">
|
||||||
<ul class="uk-nav uk-dropdown-nav">
|
<ul class="uk-nav uk-dropdown-nav">
|
||||||
<li>
|
|
||||||
<div on:click={() => drillIntoRecord(row)}>View</div>
|
|
||||||
</li>
|
|
||||||
<li
|
<li
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
editRecord(row)
|
editRecord(row)
|
||||||
|
|
|
@ -1,231 +0,0 @@
|
||||||
<script>
|
|
||||||
import { tick } from "svelte"
|
|
||||||
import Textbox from "components/common/Textbox.svelte"
|
|
||||||
import Button from "components/common/Button.svelte"
|
|
||||||
import Select from "components/common/Select.svelte"
|
|
||||||
import ActionButton from "components/common/ActionButton.svelte"
|
|
||||||
import getIcon from "components/common/icon"
|
|
||||||
import FieldView from "../../FieldView.svelte"
|
|
||||||
import {
|
|
||||||
get,
|
|
||||||
compose,
|
|
||||||
map,
|
|
||||||
join,
|
|
||||||
filter,
|
|
||||||
some,
|
|
||||||
find,
|
|
||||||
keys,
|
|
||||||
isDate,
|
|
||||||
} from "lodash/fp"
|
|
||||||
import { store, backendUiStore } from "builderStore"
|
|
||||||
import { common, hierarchy } from "../../../../../../core/src/"
|
|
||||||
import { getNode } from "components/common/core"
|
|
||||||
import { templateApi, pipe, validate } from "components/common/core"
|
|
||||||
import ErrorsBox from "components/common/ErrorsBox.svelte"
|
|
||||||
|
|
||||||
let model
|
|
||||||
let editingField = false
|
|
||||||
let fieldToEdit
|
|
||||||
let isNewField = false
|
|
||||||
let newField
|
|
||||||
let editField
|
|
||||||
let deleteField
|
|
||||||
let onFinishedFieldEdit
|
|
||||||
let editIndex
|
|
||||||
|
|
||||||
$: parent = model && model.parent()
|
|
||||||
$: isChildModel = parent && parent.name !== "root"
|
|
||||||
$: modelExistsInHierarchy =
|
|
||||||
$store.currentNode && getNode($store.hierarchy, $store.currentNode.nodeId)
|
|
||||||
|
|
||||||
store.subscribe($store => {
|
|
||||||
model = $store.currentNode
|
|
||||||
const flattened = hierarchy.getFlattenedHierarchy($store.hierarchy)
|
|
||||||
|
|
||||||
newField = () => {
|
|
||||||
isNewField = true
|
|
||||||
fieldToEdit = templateApi($store.hierarchy).getNewField("string")
|
|
||||||
editingField = true
|
|
||||||
}
|
|
||||||
|
|
||||||
onFinishedFieldEdit = field => {
|
|
||||||
if (field) {
|
|
||||||
store.saveField(field)
|
|
||||||
}
|
|
||||||
editingField = false
|
|
||||||
}
|
|
||||||
|
|
||||||
editField = field => {
|
|
||||||
isNewField = false
|
|
||||||
fieldToEdit = field
|
|
||||||
editingField = true
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteField = field => {
|
|
||||||
store.deleteField(field)
|
|
||||||
}
|
|
||||||
|
|
||||||
editIndex = index => {
|
|
||||||
store.selectExistingNode(index.nodeId)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
let getTypeOptionsValueText = value => {
|
|
||||||
if (
|
|
||||||
value === Number.MAX_SAFE_INTEGER ||
|
|
||||||
value === Number.MIN_SAFE_INTEGER ||
|
|
||||||
new Date(value).getTime() === new Date(8640000000000000).getTime() ||
|
|
||||||
new Date(value).getTime() === new Date(-8640000000000000).getTime()
|
|
||||||
)
|
|
||||||
return "(any)"
|
|
||||||
|
|
||||||
if (value === null) return "(not set)"
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
const nameChanged = ev => {
|
|
||||||
const pluralName = n => `${n}s`
|
|
||||||
if (model.collectionName === "") {
|
|
||||||
model.collectionName = pluralName(ev.target.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<heading>
|
|
||||||
{#if !editingField}
|
|
||||||
<i class="ri-list-settings-line button--toggled" />
|
|
||||||
<h3 class="budibase__title--3">Create / Edit Model</h3>
|
|
||||||
{:else}
|
|
||||||
<i class="ri-file-list-line button--toggled" />
|
|
||||||
<h3 class="budibase__title--3">Create / Edit Field</h3>
|
|
||||||
{/if}
|
|
||||||
</heading>
|
|
||||||
{#if !editingField}
|
|
||||||
<div class="padding">
|
|
||||||
<h4 class="budibase__label--big">Settings</h4>
|
|
||||||
|
|
||||||
{#if $store.errors && $store.errors.length > 0}
|
|
||||||
<ErrorsBox errors={$store.errors} />
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<form on:submit|preventDefault class="uk-form-stacked">
|
|
||||||
|
|
||||||
<Textbox label="Name" bind:text={model.name} on:change={nameChanged} />
|
|
||||||
{#if isChildModel}
|
|
||||||
<div>
|
|
||||||
<label class="uk-form-label">Parent</label>
|
|
||||||
<div class="uk-form-controls parent-name">{parent.name}</div>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<div class="table-controls">
|
|
||||||
<span class="budibase__label--big">Fields</span>
|
|
||||||
<h4 class="hoverable new-field" on:click={newField}>Add new field</h4>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<table class="uk-table fields-table budibase__table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Edit</th>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Type</th>
|
|
||||||
<th>Values</th>
|
|
||||||
<th />
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{#each model ? model.fields : [] as field}
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<i class="ri-more-line" on:click={() => editField(field)} />
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div>{field.name}</div>
|
|
||||||
</td>
|
|
||||||
<td>{field.type}</td>
|
|
||||||
<td>{field.typeOptions.values || ''}</td>
|
|
||||||
<td>
|
|
||||||
<i
|
|
||||||
class="ri-delete-bin-6-line hoverable"
|
|
||||||
on:click={() => deleteField(field)} />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{/each}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<div class="uk-margin">
|
|
||||||
<ActionButton color="secondary" on:click={store.saveCurrentNode}>
|
|
||||||
Save
|
|
||||||
</ActionButton>
|
|
||||||
{#if modelExistsInHierarchy}
|
|
||||||
<ActionButton color="primary" on:click={store.newChildModel}>
|
|
||||||
Create Child Model on {model.name}
|
|
||||||
</ActionButton>
|
|
||||||
<ActionButton
|
|
||||||
color="primary"
|
|
||||||
on:click={async () => {
|
|
||||||
backendUiStore.actions.modals.show('VIEW')
|
|
||||||
await tick()
|
|
||||||
store.newChildIndex()
|
|
||||||
}}>
|
|
||||||
Create Child View on {model.name}
|
|
||||||
</ActionButton>
|
|
||||||
<ActionButton alert on:click={store.deleteCurrentNode}>
|
|
||||||
Delete
|
|
||||||
</ActionButton>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{:else}
|
|
||||||
<FieldView
|
|
||||||
field={fieldToEdit}
|
|
||||||
onFinished={onFinishedFieldEdit}
|
|
||||||
allFields={model.fields}
|
|
||||||
store={$store} />
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.padding {
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.new-field {
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: var(--button-text);
|
|
||||||
}
|
|
||||||
|
|
||||||
.fields-table {
|
|
||||||
margin: 1rem 1rem 0rem 0rem;
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
|
|
||||||
tbody > tr:hover {
|
|
||||||
background-color: var(--primary10);
|
|
||||||
}
|
|
||||||
|
|
||||||
.table-controls {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ri-more-line:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
heading {
|
|
||||||
padding: 20px 20px 0 20px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
margin: 0 0 0 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.parent-name {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -29,7 +29,6 @@
|
||||||
: []
|
: []
|
||||||
|
|
||||||
function closed() {
|
function closed() {
|
||||||
// editingRecord = null
|
|
||||||
onClosed()
|
onClosed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,7 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}],
|
}],
|
||||||
appRootPath: `/`,
|
appRootPath: ""
|
||||||
}
|
}
|
||||||
|
|
||||||
$: selectedComponentId = $store.currentComponentInfo ? $store.currentComponentInfo._id : ""
|
$: selectedComponentId = $store.currentComponentInfo ? $store.currentComponentInfo._id : ""
|
||||||
|
|
|
@ -88,11 +88,6 @@ const parsePropDef = propDef => {
|
||||||
const type = TYPE_MAP[propDef.type]
|
const type = TYPE_MAP[propDef.type]
|
||||||
if (!type) return error(`Type ${propDef.type} is not recognised.`)
|
if (!type) return error(`Type ${propDef.type} is not recognised.`)
|
||||||
|
|
||||||
// if (isUndefined(propDef.default)) return type.default(propDef)
|
|
||||||
|
|
||||||
// if (!type.isOfType(propDef.default))
|
|
||||||
// return error(`${propDef.default} is not of type ${type}`)
|
|
||||||
|
|
||||||
return propDef.default
|
return propDef.default
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,86 +0,0 @@
|
||||||
const { readdir, stat, copyFile } = require("fs-extra")
|
|
||||||
const { constants } = require("fs")
|
|
||||||
const { join, basename } = require("path")
|
|
||||||
const serverConfig = require("../../../server/config")()
|
|
||||||
|
|
||||||
const packagesFolder = ".."
|
|
||||||
|
|
||||||
const jsFile = dir => join(dir, "index.js")
|
|
||||||
const jsMapFile = dir => join(dir, "index.js.map")
|
|
||||||
const sourceJs = jsFile("dist")
|
|
||||||
const sourceJsMap = jsMapFile("dist")
|
|
||||||
const componentsFile = "components.json"
|
|
||||||
|
|
||||||
const appPackages = join(
|
|
||||||
packagesFolder,
|
|
||||||
"server",
|
|
||||||
serverConfig.latestPackagesFolder
|
|
||||||
)
|
|
||||||
|
|
||||||
const publicMain = appName =>
|
|
||||||
join(
|
|
||||||
appPackages,
|
|
||||||
appName,
|
|
||||||
"public",
|
|
||||||
"main",
|
|
||||||
"lib",
|
|
||||||
"node_modules",
|
|
||||||
"@budibase",
|
|
||||||
"standard-components"
|
|
||||||
)
|
|
||||||
const publicUnauth = appName =>
|
|
||||||
join(
|
|
||||||
appPackages,
|
|
||||||
appName,
|
|
||||||
"public",
|
|
||||||
"unauthenticated",
|
|
||||||
"lib",
|
|
||||||
"node_modules",
|
|
||||||
"@budibase",
|
|
||||||
"standard-components"
|
|
||||||
)
|
|
||||||
const nodeModulesDist = appName =>
|
|
||||||
join(
|
|
||||||
appPackages,
|
|
||||||
appName,
|
|
||||||
"node_modules",
|
|
||||||
"@budibase",
|
|
||||||
"standard-components",
|
|
||||||
"dist"
|
|
||||||
)
|
|
||||||
const nodeModules = appName =>
|
|
||||||
join(appPackages, appName, "node_modules", "@budibase", "standard-components")
|
|
||||||
|
|
||||||
;(async () => {
|
|
||||||
const apps = await readdir(appPackages)
|
|
||||||
|
|
||||||
const copySource = file => async toDir => {
|
|
||||||
const dest = join(toDir, basename(file))
|
|
||||||
try {
|
|
||||||
await copyFile(file, dest, constants.COPYFILE_FICLONE)
|
|
||||||
console.log(`COPIED ${file} to ${dest}`)
|
|
||||||
} catch (e) {
|
|
||||||
console.log(`COPY FAILED ${file} to ${dest}: ${e}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const copySourceJs = copySource(sourceJs)
|
|
||||||
const copySourceJsMap = copySource(sourceJsMap)
|
|
||||||
const copyComponentsJson = copySource(componentsFile)
|
|
||||||
|
|
||||||
for (let app of apps) {
|
|
||||||
if (app === ".data") continue
|
|
||||||
if (!(await stat(join(appPackages, app))).isDirectory()) continue
|
|
||||||
|
|
||||||
await copySourceJs(nodeModulesDist(app))
|
|
||||||
await copySourceJsMap(nodeModulesDist(app))
|
|
||||||
|
|
||||||
await copyComponentsJson(nodeModules(app))
|
|
||||||
|
|
||||||
await copySourceJs(join(publicMain(app), "dist"))
|
|
||||||
await copySourceJsMap(join(publicMain(app), "dist"))
|
|
||||||
|
|
||||||
await copySourceJs(join(publicUnauth(app), "dist"))
|
|
||||||
await copySourceJsMap(join(publicUnauth(app), "dist"))
|
|
||||||
}
|
|
||||||
})()
|
|
|
@ -37,10 +37,14 @@ exports.authenticate = async ctx => {
|
||||||
accessLevel: "",
|
accessLevel: "",
|
||||||
instanceId: instanceId
|
instanceId: instanceId
|
||||||
};
|
};
|
||||||
const token = jwt.sign(payload, ctx.config.secret, {
|
|
||||||
|
|
||||||
|
const token = jwt.sign(payload, ctx.config.jwtSecret, {
|
||||||
expiresIn: "1 day"
|
expiresIn: "1 day"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ctx.cookies.set('budibase:token', token);
|
||||||
|
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
token,
|
token,
|
||||||
...dbUser
|
...dbUser
|
||||||
|
|
|
@ -31,18 +31,16 @@ module.exports = app => {
|
||||||
flush: zlib.Z_SYNC_FLUSH,
|
flush: zlib.Z_SYNC_FLUSH,
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
.use(authenticated)
|
|
||||||
.use(async (ctx, next) => {
|
.use(async (ctx, next) => {
|
||||||
// TODO: temp dev middleware
|
// TODO: temp dev middleware
|
||||||
// ctx.sessionId = ctx.session._sessCtx.externalKey
|
|
||||||
// ctx.session.accessed = true
|
|
||||||
ctx.config = {
|
ctx.config = {
|
||||||
latestPackagesFolder: resolve(homedir(), ".budibase"),
|
latestPackagesFolder: resolve(homedir(), ".budibase"),
|
||||||
secret: "foo"
|
jwtSecret: "foo"
|
||||||
}
|
}
|
||||||
ctx.isDev = process.env.NODE_ENV !== "production";
|
ctx.isDev = process.env.NODE_ENV !== "production";
|
||||||
await next();
|
await next();
|
||||||
});
|
})
|
||||||
|
.use(authenticated);
|
||||||
|
|
||||||
// error handling middleware
|
// error handling middleware
|
||||||
router.use(async (ctx, next) => {
|
router.use(async (ctx, next) => {
|
||||||
|
@ -61,15 +59,26 @@ module.exports = app => {
|
||||||
router.use(authRoutes.routes());
|
router.use(authRoutes.routes());
|
||||||
router.use(authRoutes.allowedMethods());
|
router.use(authRoutes.allowedMethods());
|
||||||
|
|
||||||
router.use(pageRoutes.routes());
|
// authenticated routes
|
||||||
router.use(pageRoutes.allowedMethods());
|
|
||||||
|
|
||||||
router.use(viewRoutes.routes());
|
router.use(viewRoutes.routes());
|
||||||
router.use(viewRoutes.allowedMethods());
|
router.use(viewRoutes.allowedMethods());
|
||||||
|
|
||||||
router.use(modelRoutes.routes());
|
router.use(modelRoutes.routes());
|
||||||
router.use(modelRoutes.allowedMethods());
|
router.use(modelRoutes.allowedMethods());
|
||||||
|
|
||||||
|
router.use(userRoutes.routes());
|
||||||
|
router.use(userRoutes.allowedMethods());
|
||||||
|
|
||||||
|
router.use(recordRoutes.routes());
|
||||||
|
router.use(recordRoutes.allowedMethods());
|
||||||
|
|
||||||
|
router.use(instanceRoutes.routes());
|
||||||
|
router.use(instanceRoutes.allowedMethods());
|
||||||
|
// end auth routes
|
||||||
|
|
||||||
|
router.use(pageRoutes.routes());
|
||||||
|
router.use(pageRoutes.allowedMethods());
|
||||||
|
|
||||||
router.use(applicationRoutes.routes());
|
router.use(applicationRoutes.routes());
|
||||||
router.use(applicationRoutes.allowedMethods());
|
router.use(applicationRoutes.allowedMethods());
|
||||||
|
|
||||||
|
@ -79,15 +88,6 @@ module.exports = app => {
|
||||||
router.use(clientRoutes.routes());
|
router.use(clientRoutes.routes());
|
||||||
router.use(clientRoutes.allowedMethods());
|
router.use(clientRoutes.allowedMethods());
|
||||||
|
|
||||||
router.use(userRoutes.routes());
|
|
||||||
router.use(userRoutes.allowedMethods());
|
|
||||||
|
|
||||||
router.use(recordRoutes.routes());
|
|
||||||
router.use(recordRoutes.allowedMethods());
|
|
||||||
|
|
||||||
router.use(instanceRoutes.routes());
|
|
||||||
router.use(instanceRoutes.allowedMethods());
|
|
||||||
|
|
||||||
router.use(staticRoutes.routes());
|
router.use(staticRoutes.routes());
|
||||||
router.use(staticRoutes.allowedMethods());
|
router.use(staticRoutes.allowedMethods());
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ router
|
||||||
.param("file", async (file, ctx, next) => {
|
.param("file", async (file, ctx, next) => {
|
||||||
ctx.file = file && file.includes(".") ? file : "index.html";
|
ctx.file = file && file.includes(".") ? file : "index.html";
|
||||||
|
|
||||||
// Serving the latest client library in dev
|
// Serving the client library from your local dir in dev
|
||||||
if (ctx.isDev && ctx.file.startsWith("budibase-client")) {
|
if (ctx.isDev && ctx.file.startsWith("budibase-client")) {
|
||||||
ctx.devPath = "/tmp/.budibase";
|
ctx.devPath = "/tmp/.budibase";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
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
|
|
||||||
}
|
|
|
@ -1,17 +1,17 @@
|
||||||
const jwt = require("jsonwebtoken");
|
const jwt = require("jsonwebtoken");
|
||||||
|
|
||||||
module.exports = async (ctx, next) => {
|
module.exports = async (ctx, next) => {
|
||||||
if (!ctx.headers.authorization) {
|
const token = ctx.cookies.get("budibase:token");
|
||||||
|
console.log("TOKEN", token);
|
||||||
|
|
||||||
|
if (!token) {
|
||||||
ctx.isAuthenticated = false
|
ctx.isAuthenticated = false
|
||||||
await next();
|
await next();
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
// if (!ctx.headers.authorization) ctx.throw(403, "No token provided");
|
|
||||||
|
|
||||||
const [_, token] = ctx.headers.authorization.split(" ");
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ctx.request.jwtPayload = jwt.verify(token, ctx.config.jwtSecret);
|
ctx.jwtPayload = jwt.verify(token, ctx.config.jwtSecret);
|
||||||
ctx.isAuthenticated = true;
|
ctx.isAuthenticated = true;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
ctx.throw(err.status || 403, err.text);
|
ctx.throw(err.status || 403, err.text);
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
const StatusCodes = require("../../utilities/statusCodes")
|
|
||||||
const { getRecordKey } = require("./helpers")
|
|
||||||
|
|
||||||
module.exports = async ctx => {
|
|
||||||
const indexkey = getRecordKey(ctx.params.appname, ctx.request.path)
|
|
||||||
ctx.body = await ctx.instance.indexApi.aggregates(indexkey, {
|
|
||||||
rangeStartParams: ctx.request.body.rangeStartParams,
|
|
||||||
rangeEndParams: ctx.request.body.rangeEndParams,
|
|
||||||
searchPhrase: ctx.request.body.searchPhrase,
|
|
||||||
})
|
|
||||||
ctx.response.status = StatusCodes.OK
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
const { getAppRelativePath } = require("./helpers")
|
|
||||||
|
|
||||||
const send = require("koa-send")
|
|
||||||
|
|
||||||
module.exports = async (ctx, next) => {
|
|
||||||
const path = getAppRelativePath(ctx.params.appname, ctx.path)
|
|
||||||
|
|
||||||
if (path.startsWith("/api/")) {
|
|
||||||
await next()
|
|
||||||
} else if (path.startsWith("/_shared/")) {
|
|
||||||
await send(ctx, path.replace(`/_shared/`, ""), { root: ctx.sharedPath })
|
|
||||||
} else if (
|
|
||||||
path.endsWith(".js") ||
|
|
||||||
path.endsWith(".map") ||
|
|
||||||
path.endsWith(".css")
|
|
||||||
) {
|
|
||||||
await send(ctx, path, { root: ctx.publicPath })
|
|
||||||
} else {
|
|
||||||
await send(ctx, "/index.html", { root: ctx.publicPath })
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
const StatusCodes = require("../../utilities/statusCodes")
|
|
||||||
|
|
||||||
module.exports = async ctx => {
|
|
||||||
const user = await ctx.master.authenticate(
|
|
||||||
ctx.sessionId,
|
|
||||||
ctx.params.appname,
|
|
||||||
ctx.request.body.username,
|
|
||||||
ctx.request.body.password
|
|
||||||
)
|
|
||||||
if (!user) {
|
|
||||||
ctx.throw(StatusCodes.UNAUTHORIZED, "invalid username or password")
|
|
||||||
}
|
|
||||||
ctx.body = user.user_json
|
|
||||||
ctx.response.status = StatusCodes.OK
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
const StatusCodes = require("../../utilities/statusCodes")
|
|
||||||
|
|
||||||
module.exports = async ctx => {
|
|
||||||
await ctx.instance.authApi.changeMyPassword(
|
|
||||||
ctx.request.body.currentPassword,
|
|
||||||
ctx.request.body.newPassword
|
|
||||||
)
|
|
||||||
ctx.response.status = StatusCodes.OK
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
const StatusCodes = require("../../utilities/statusCodes")
|
|
||||||
|
|
||||||
module.exports = async ctx => {
|
|
||||||
const instanceApi = await ctx.master.getFullAccessInstanceApiForUsername(
|
|
||||||
ctx.params.appname,
|
|
||||||
ctx.request.body.username
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!instanceApi) {
|
|
||||||
ctx.request.status = StatusCodes.OK
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
await instanceApi.authApi.createTemporaryAccess(ctx.request.body.username)
|
|
||||||
|
|
||||||
ctx.response.status = StatusCodes.OK
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
const StatusCodes = require("../../utilities/statusCodes")
|
|
||||||
|
|
||||||
module.exports = async ctx => {
|
|
||||||
await ctx.instance.authApi.createUser(
|
|
||||||
ctx.request.body.user,
|
|
||||||
ctx.request.body.password
|
|
||||||
)
|
|
||||||
|
|
||||||
ctx.response.status = StatusCodes.OK
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
const StatusCodes = require("../../utilities/statusCodes")
|
|
||||||
const { getRecordKey } = require("./helpers")
|
|
||||||
|
|
||||||
module.exports = async ctx => {
|
|
||||||
await ctx.instance.recordApi.delete(
|
|
||||||
getRecordKey(ctx.params.appname, ctx.request.path)
|
|
||||||
)
|
|
||||||
ctx.response.status = StatusCodes.OK
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
const StatusCodes = require("../../utilities/statusCodes")
|
|
||||||
|
|
||||||
module.exports = async ctx => {
|
|
||||||
await ctx.instance.authApi.disableUser(ctx.request.body.username)
|
|
||||||
|
|
||||||
await ctx.master.removeSessionsForUser(
|
|
||||||
ctx.params.appname,
|
|
||||||
ctx.request.body.username
|
|
||||||
)
|
|
||||||
ctx.response.status = StatusCodes.OK
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
const StatusCodes = require("../../utilities/statusCodes")
|
|
||||||
|
|
||||||
module.exports = async ctx => {
|
|
||||||
await ctx.instance.authApi.enableUser(ctx.request.body.username)
|
|
||||||
ctx.response.status = StatusCodes.OK
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
const StatusCodes = require("../../utilities/statusCodes")
|
|
||||||
|
|
||||||
module.exports = async ctx => {
|
|
||||||
ctx.body = await ctx.instance.actionApi.execute(
|
|
||||||
ctx.request.body.actionname,
|
|
||||||
ctx.request.body.parameters
|
|
||||||
)
|
|
||||||
ctx.response.status = StatusCodes.OK
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
const StatusCodes = require("../../utilities/statusCodes")
|
|
||||||
|
|
||||||
module.exports = async ctx => {
|
|
||||||
ctx.body = await ctx.instance.authApi.getAccessLevels()
|
|
||||||
ctx.response.status = StatusCodes.OK
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
const StatusCodes = require("../../utilities/statusCodes")
|
|
||||||
const { getRecordKey } = require("./helpers")
|
|
||||||
|
|
||||||
module.exports = async ctx => {
|
|
||||||
try {
|
|
||||||
ctx.body = await ctx.instance.recordApi.load(
|
|
||||||
getRecordKey(ctx.params.appname, ctx.request.path)
|
|
||||||
)
|
|
||||||
ctx.response.status = StatusCodes.OK
|
|
||||||
} catch (e) {
|
|
||||||
// need to be catching for 404s here
|
|
||||||
ctx.response.status = StatusCodes.INTERAL_ERROR
|
|
||||||
ctx.response.body = e.message
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
const StatusCodes = require("../../utilities/statusCodes")
|
|
||||||
|
|
||||||
module.exports = async ctx => {
|
|
||||||
ctx.body = await ctx.instance.authApi.getUsers()
|
|
||||||
ctx.response.status = StatusCodes.OK
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
exports.getRecordKey = (appname, wholePath) =>
|
|
||||||
this.getAppRelativePath(appname, wholePath)
|
|
||||||
.replace(`/api/files/`, "/")
|
|
||||||
.replace(`/api/lookup_field/`, "/")
|
|
||||||
.replace(`/api/record/`, "/")
|
|
||||||
.replace(`/api/listRecords/`, "/")
|
|
||||||
.replace(`/api/aggregates/`, "/")
|
|
||||||
|
|
||||||
exports.getAppRelativePath = (appname, wholePath) => {
|
|
||||||
const builderInstanceRegex = new RegExp(
|
|
||||||
`\\/_builder\\/instance\\/[^\\/]*\\/[^\\/]*\\/`
|
|
||||||
)
|
|
||||||
|
|
||||||
return wholePath.replace(builderInstanceRegex, "/").replace(`/${appname}`, "")
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
const authenticate = require("./authenticate")
|
|
||||||
const setPasswordFromTemporaryCode = require("./setPasswordFromTemporaryCode")
|
|
||||||
const createTemporaryAccess = require("./createTemporaryAccess")
|
|
||||||
const appDefault = require("./appDefault")
|
|
||||||
const changeMyPassword = require("./changeMyPassword")
|
|
||||||
const executeAction = require("./executeAction")
|
|
||||||
const createUser = require("./createUser")
|
|
||||||
const enableUser = require("./enableUser")
|
|
||||||
const disableUser = require("./disableUser")
|
|
||||||
const getUsers = require("./getUsers")
|
|
||||||
const getAccessLevels = require("./getAccessLevels")
|
|
||||||
const listRecordsGet = require("./listRecordsGet")
|
|
||||||
const listRecordsPost = require("./listRecordsPost")
|
|
||||||
const aggregatesPost = require("./aggregatesPost")
|
|
||||||
const postFiles = require("./postFiles")
|
|
||||||
const saveRecord = require("./saveRecord")
|
|
||||||
const lookupField = require("./lookupField")
|
|
||||||
const getRecord = require("./getRecord")
|
|
||||||
const deleteRecord = require("./deleteRecord")
|
|
||||||
const saveAppHierarchy = require("./saveAppHierarchy")
|
|
||||||
const upgradeData = require("./upgradeData")
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
authenticate,
|
|
||||||
setPasswordFromTemporaryCode,
|
|
||||||
createTemporaryAccess,
|
|
||||||
appDefault,
|
|
||||||
changeMyPassword,
|
|
||||||
executeAction,
|
|
||||||
createUser,
|
|
||||||
enableUser,
|
|
||||||
disableUser,
|
|
||||||
getUsers,
|
|
||||||
getAccessLevels,
|
|
||||||
listRecordsGet,
|
|
||||||
listRecordsPost,
|
|
||||||
aggregatesPost,
|
|
||||||
postFiles,
|
|
||||||
saveRecord,
|
|
||||||
lookupField,
|
|
||||||
getRecord,
|
|
||||||
deleteRecord,
|
|
||||||
saveAppHierarchy,
|
|
||||||
upgradeData,
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
const StatusCodes = require("../../utilities/statusCodes")
|
|
||||||
const { getRecordKey } = require("./helpers")
|
|
||||||
|
|
||||||
module.exports = async ctx => {
|
|
||||||
const indexkey = getRecordKey(ctx.params.appname, ctx.request.path)
|
|
||||||
ctx.body = await ctx.instance.indexApi.listItems(indexkey)
|
|
||||||
ctx.response.status = StatusCodes.OK
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
const StatusCodes = require("../../utilities/statusCodes")
|
|
||||||
const { getRecordKey } = require("./helpers")
|
|
||||||
|
|
||||||
module.exports = async ctx => {
|
|
||||||
const indexkey = getRecordKey(ctx.params.appname, ctx.request.path)
|
|
||||||
ctx.body = await ctx.instance.indexApi.listItems(indexkey, {
|
|
||||||
rangeStartParams: ctx.request.body.rangeStartParams,
|
|
||||||
rangeEndParams: ctx.request.body.rangeEndParams,
|
|
||||||
searchPhrase: ctx.request.body.searchPhrase,
|
|
||||||
})
|
|
||||||
ctx.response.status = StatusCodes.OK
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
const StatusCodes = require("../../utilities/statusCodes")
|
|
||||||
const { getRecordKey } = require("./helpers")
|
|
||||||
|
|
||||||
module.exports = 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
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
const StatusCodes = require("../../utilities/statusCodes")
|
|
||||||
const { getRecordKey } = require("./helpers")
|
|
||||||
const fs = require("fs")
|
|
||||||
|
|
||||||
module.exports = async ctx => {
|
|
||||||
const file = ctx.request.files.file
|
|
||||||
ctx.body = await ctx.instance.recordApi.uploadFile(
|
|
||||||
getRecordKey(ctx.params.appname, ctx.request.path),
|
|
||||||
fs.createReadStream(file.path),
|
|
||||||
file.name
|
|
||||||
)
|
|
||||||
ctx.response.status = StatusCodes.OK
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
const StatusCodes = require("../../utilities/statusCodes")
|
|
||||||
|
|
||||||
module.exports = async ctx => {
|
|
||||||
ctx.body = await ctx.instance.templateApi.saveApplicationHierarchy(ctx.body)
|
|
||||||
ctx.response.status = StatusCodes.OK
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
const StatusCodes = require("../../utilities/statusCodes")
|
|
||||||
|
|
||||||
module.exports = async ctx => {
|
|
||||||
ctx.body = await ctx.instance.recordApi.save(ctx.request.body)
|
|
||||||
ctx.response.status = StatusCodes.OK
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
const StatusCodes = require("../../utilities/statusCodes")
|
|
||||||
|
|
||||||
module.exports = async ctx => {
|
|
||||||
const instanceApi = await ctx.master.getFullAccessInstanceApiForUsername(
|
|
||||||
ctx.params.appname,
|
|
||||||
ctx.request.body.username
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!instanceApi) {
|
|
||||||
ctx.request.status = StatusCodes.OK
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
await instanceApi.authApi.setPasswordFromTemporaryCode(
|
|
||||||
ctx.request.body.tempCode,
|
|
||||||
ctx.request.body.newPassword
|
|
||||||
)
|
|
||||||
|
|
||||||
ctx.response.status = StatusCodes.OK
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
const StatusCodes = require("../../utilities/statusCodes")
|
|
||||||
|
|
||||||
module.exports = async ctx => {
|
|
||||||
const existingAccessLevels = await ctx.instance.authApi.loadAccessLevels()
|
|
||||||
const accessLevels = ctx.request.body.accessLevels
|
|
||||||
accessLevels.version = existingAccessLevels.version
|
|
||||||
await ctx.instance.authApi.saveAccessLevels(accessLevels)
|
|
||||||
await ctx.instance.templateApi.upgradeData(ctx.request.body.newHierarchy)
|
|
||||||
await ctx.master.clearAllSessions(ctx.params.appname)
|
|
||||||
ctx.response.status = StatusCodes.OK
|
|
||||||
}
|
|
|
@ -265,13 +265,13 @@
|
||||||
"datatable": {
|
"datatable": {
|
||||||
"description": "an HTML table that fetches data from a model or view and displays it.",
|
"description": "an HTML table that fetches data from a model or view and displays it.",
|
||||||
"props": {
|
"props": {
|
||||||
"_viewName": "string",
|
|
||||||
"_instanceId": "string",
|
"_instanceId": "string",
|
||||||
"model": {
|
"model": {
|
||||||
"type": "options",
|
"type": "options",
|
||||||
"default": "",
|
"default": "",
|
||||||
"options": [
|
"options": [
|
||||||
"all_6dc86335-83b7-462c-90ca-1fe7feb08942"
|
"all_6dc86335-83b7-462c-90ca-1fe7feb08942",
|
||||||
|
"all_fcd00735-01f0-451c-819e-902a3ea53c26"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,28 +5,23 @@
|
||||||
|
|
||||||
export let _bb
|
export let _bb
|
||||||
export let onLoad
|
export let onLoad
|
||||||
export let _viewName
|
|
||||||
export let _instanceId
|
export let _instanceId
|
||||||
|
export let model
|
||||||
|
|
||||||
let cssVariables
|
let cssVariables
|
||||||
let headers = []
|
let headers = []
|
||||||
let data = []
|
let data = []
|
||||||
|
|
||||||
async function fetchData() {
|
async function fetchData() {
|
||||||
const FETCH_RECORDS_URL = `/api/${_instanceId}/${_viewName}/records`;
|
const FETCH_RECORDS_URL = `/api/${_instanceId}/${model}/records`;
|
||||||
const response = await _bb.api.get(FETCH_RECORDS_URL);
|
const response = await _bb.api.get(FETCH_RECORDS_URL);
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
const json = await response.json();
|
const json = await response.json();
|
||||||
|
|
||||||
if (json.length > 0) {
|
|
||||||
data = json;
|
data = json;
|
||||||
headers = Object.keys(data[0]);
|
headers = Object.keys(data[0]).filter(key => !key.startsWith("_"));
|
||||||
} else {
|
} else {
|
||||||
console.log("NO DATA");
|
throw new Error("Failed to fetch records.", response);
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new Error("Failed to fetch records..");
|
|
||||||
console.log("FAILED");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
const login = async () => {
|
const login = async () => {
|
||||||
loading = true
|
loading = true
|
||||||
const response = _bb.api.post("/api/authenticate", { username, password });
|
const response = await _bb.api.post("/api/authenticate", { username, password });
|
||||||
|
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
const json = await response.json();
|
const json = await response.json();
|
||||||
|
|
Loading…
Reference in New Issue