1
0
Fork 0
mirror of synced 2024-06-30 12:00:31 +12:00

pouchDB integration, use app id instead of app name for keying app packages

This commit is contained in:
Martin McKeaveney 2020-04-23 14:37:08 +01:00
parent 228999aba5
commit 8a7c0f8ba3
43 changed files with 1017 additions and 897 deletions

View file

@ -1,34 +1,34 @@
import { flatten, values, uniq, map } from "lodash/fp" import { flatten, values, uniq, map } from "lodash/fp"
import { pipe } from "components/common/core" import { pipe } from "components/common/core"
export const loadLibs = async (appName, appPackage) => { export const loadLibs = async (appId, appPackage) => {
const allLibraries = {} const allLibraries = {}
for (let lib of libsFromPages(appPackage.pages)) { for (let lib of libsFromPages(appPackage.pages)) {
const libModule = await import(makeLibraryUrl(appName, lib)) const libModule = await import(makeLibraryUrl(appId, lib))
allLibraries[lib] = libModule allLibraries[lib] = libModule
} }
return allLibraries return allLibraries
} }
export const loadLibUrls = (appName, appPackage) => { export const loadLibUrls = (appId, appPackage) => {
const allLibraries = [] const allLibraries = []
for (let lib of libsFromPages(appPackage.pages)) { for (let lib of libsFromPages(appPackage.pages)) {
const libUrl = makeLibraryUrl(appName, lib) const libUrl = makeLibraryUrl(appId, lib)
allLibraries.push({ libName: lib, importPath: libUrl }) allLibraries.push({ libName: lib, importPath: libUrl })
} }
return allLibraries return allLibraries
} }
export const loadLib = async (appName, lib, allLibs) => { export const loadLib = async (appId, lib, allLibs) => {
allLibs[lib] = await import(makeLibraryUrl(appName, lib)) allLibs[lib] = await import(makeLibraryUrl(appId, lib))
return allLibs return allLibs
} }
export const makeLibraryUrl = (appName, lib) => export const makeLibraryUrl = (appId, lib) =>
`/_builder/${appName}/componentlibrary?lib=${encodeURI(lib)}` `/_builder/${appId}/componentlibrary?lib=${encodeURI(lib)}`
export const libsFromPages = pages => export const libsFromPages = pages =>
pipe(pages, [values, map(p => p.componentLibraries), flatten, uniq]) pipe(pages, [values, map(p => p.componentLibraries), flatten, uniq])

View file

@ -1,15 +1,9 @@
import { writable } from "svelte/store" import { writable } from "svelte/store"
import api from "../api" import api from "../api"
import { cloneDeep, sortBy, find, remove } from "lodash/fp" import { find } from "lodash/fp"
import { hierarchy as hierarchyFunctions } from "../../../../core/src"
import { import {
getNode, getNode,
validate,
constructHierarchy, constructHierarchy,
templateApi,
isIndex,
canDeleteIndex,
canDeleteModel,
} from "components/common/core" } from "components/common/core"
export const getBackendUiStore = () => { export const getBackendUiStore = () => {
@ -20,6 +14,7 @@ export const getBackendUiStore = () => {
}, },
breadcrumbs: [], breadcrumbs: [],
models: [], models: [],
users: [],
selectedDatabase: {}, selectedDatabase: {},
selectedModel: {}, selectedModel: {},
} }
@ -103,38 +98,24 @@ export const saveBackend = async state => {
}, },
accessLevels: state.accessLevels, accessLevels: state.accessLevels,
}) })
const instances_currentFirst = state.selectedDatabase
? [
state.appInstances.find(i => i.id === state.selectedDatabase.id),
...state.appInstances.filter(i => i.id !== state.selectedDatabase.id),
]
: state.appInstances
for (let instance of instances_currentFirst) {
await api.post(
`/_builder/instance/${state.appname}/${instance.id}/api/upgradeData`,
{ newHierarchy: state.hierarchy, accessLevels: state.accessLevels }
)
}
} }
export const newModel = (store, useRoot) => () => { // export const newModel = (store, useRoot) => () => {
store.update(state => { // store.update(state => {
state.currentNodeIsNew = true // state.currentNodeIsNew = true
const shadowHierarchy = createShadowHierarchy(state.hierarchy) // const shadowHierarchy = createShadowHierarchy(state.hierarchy)
const parent = useRoot // const parent = useRoot
? shadowHierarchy // ? shadowHierarchy
: getNode(shadowHierarchy, state.currentNode.nodeId) // : getNode(shadowHierarchy, state.currentNode.nodeId)
state.errors = [] // state.errors = []
state.currentNode = templateApi(shadowHierarchy).getNewModelTemplate( // state.currentNode = templateApi(shadowHierarchy).getNewModelTemplate(
parent, // parent,
"", // "",
true // true
) // )
return state // return state
}) // })
} // }
export const selectExistingNode = store => nodeId => { export const selectExistingNode = store => nodeId => {
store.update(state => { store.update(state => {
@ -145,133 +126,133 @@ export const selectExistingNode = store => nodeId => {
}) })
} }
export const newIndex = (store, useRoot) => () => { // export const newIndex = (store, useRoot) => () => {
store.update(state => { // store.update(state => {
state.shadowHierarchy = createShadowHierarchy(state.hierarchy) // state.shadowHierarchy = createShadowHierarchy(state.hierarchy)
state.currentNodeIsNew = true // state.currentNodeIsNew = true
state.errors = [] // state.errors = []
const parent = useRoot // const parent = useRoot
? state.shadowHierarchy // ? state.shadowHierarchy
: getNode(state.shadowHierarchy, state.currentNode.nodeId) // : getNode(state.shadowHierarchy, state.currentNode.nodeId)
state.currentNode = templateApi(state.shadowHierarchy).getNewIndexTemplate( // state.currentNode = templateApi(state.shadowHierarchy).getNewIndexTemplate(
parent // parent
) // )
return state // return state
}) // })
} // }
export const saveCurrentNode = store => () => { // export const saveCurrentNode = store => () => {
store.update(state => { // store.update(state => {
const errors = validate.node(state.currentNode) // const errors = validate.node(state.currentNode)
state.errors = errors // state.errors = errors
if (errors.length > 0) { // if (errors.length > 0) {
return state // return state
} // }
const parentNode = getNode( // const parentNode = getNode(
state.hierarchy, // state.hierarchy,
state.currentNode.parent().nodeId // state.currentNode.parent().nodeId
) // )
const existingNode = getNode(state.hierarchy, state.currentNode.nodeId) // const existingNode = getNode(state.hierarchy, state.currentNode.nodeId)
let index = parentNode.children.length // let index = parentNode.children.length
if (existingNode) { // if (existingNode) {
// remove existing // // remove existing
index = existingNode.parent().children.indexOf(existingNode) // index = existingNode.parent().children.indexOf(existingNode)
if (isIndex(existingNode)) { // if (isIndex(existingNode)) {
parentNode.indexes = parentNode.indexes.filter( // parentNode.indexes = parentNode.indexes.filter(
node => node.nodeId !== existingNode.nodeId // node => node.nodeId !== existingNode.nodeId
) // )
} else { // } else {
parentNode.children = parentNode.children.filter( // parentNode.children = parentNode.children.filter(
node => node.nodeId !== existingNode.nodeId // node => node.nodeId !== existingNode.nodeId
) // )
} // }
} // }
// should add node into existing hierarchy // // should add node into existing hierarchy
const cloned = cloneDeep(state.currentNode) // const cloned = cloneDeep(state.currentNode)
templateApi(state.hierarchy).constructNode(parentNode, cloned) // templateApi(state.hierarchy).constructNode(parentNode, cloned)
if (isIndex(existingNode)) { // if (isIndex(existingNode)) {
parentNode.children = sortBy("name", parentNode.children) // parentNode.children = sortBy("name", parentNode.children)
} else { // } else {
parentNode.indexes = sortBy("name", parentNode.indexes) // parentNode.indexes = sortBy("name", parentNode.indexes)
} // }
if (!existingNode && state.currentNode.type === "record") { // if (!existingNode && state.currentNode.type === "record") {
const defaultIndex = templateApi(state.hierarchy).getNewIndexTemplate( // const defaultIndex = templateApi(state.hierarchy).getNewIndexTemplate(
cloned.parent() // cloned.parent()
) // )
defaultIndex.name = hierarchyFunctions.isTopLevelIndex(cloned) // defaultIndex.name = hierarchyFunctions.isTopLevelIndex(cloned)
? `all_${cloned.name}s` // ? `all_${cloned.name}s`
: `${cloned.parent().name}_${cloned.name}s` // : `${cloned.parent().name}_${cloned.name}s`
defaultIndex.allowedModelNodeIds = [cloned.nodeId] // defaultIndex.allowedModelNodeIds = [cloned.nodeId]
} // }
state.currentNodeIsNew = false // state.currentNodeIsNew = false
saveBackend(state) // saveBackend(state)
return state // return state
}) // })
} // }
export const deleteCurrentNode = store => () => { // export const deleteCurrentNode = store => () => {
store.update(state => { // store.update(state => {
const nodeToDelete = getNode(state.hierarchy, state.currentNode.nodeId) // const nodeToDelete = getNode(state.hierarchy, state.currentNode.nodeId)
state.currentNode = hierarchyFunctions.isRoot(nodeToDelete.parent()) // state.currentNode = hierarchyFunctions.isRoot(nodeToDelete.parent())
? state.hierarchy.children.find(node => node !== state.currentNode) // ? state.hierarchy.children.find(node => node !== state.currentNode)
: nodeToDelete.parent() // : nodeToDelete.parent()
const isModel = hierarchyFunctions.isModel(nodeToDelete) // const isModel = hierarchyFunctions.isModel(nodeToDelete)
const check = isModel // const check = isModel
? canDeleteModel(nodeToDelete) // ? canDeleteModel(nodeToDelete)
: canDeleteIndex(nodeToDelete) // : canDeleteIndex(nodeToDelete)
if (!check.canDelete) { // if (!check.canDelete) {
state.errors = check.errors.map(e => ({ error: e })) // state.errors = check.errors.map(e => ({ error: e }))
return state // return state
} // }
const recordOrIndexKey = isModel ? "children" : "indexes" // const recordOrIndexKey = isModel ? "children" : "indexes"
// remove the selected record or index // // remove the selected record or index
const newCollection = remove( // const newCollection = remove(
node => node.nodeId === nodeToDelete.nodeId, // node => node.nodeId === nodeToDelete.nodeId,
nodeToDelete.parent()[recordOrIndexKey] // nodeToDelete.parent()[recordOrIndexKey]
) // )
nodeToDelete.parent()[recordOrIndexKey] = newCollection // nodeToDelete.parent()[recordOrIndexKey] = newCollection
state.errors = [] // state.errors = []
saveBackend(state) // saveBackend(state)
return state // return state
}) // })
} // }
export const saveField = store => field => { // export const saveField = store => field => {
store.update(state => { // store.update(state => {
state.currentNode.fields = state.currentNode.fields.filter( // state.currentNode.fields = state.currentNode.fields.filter(
f => f.id !== field.id // f => f.id !== field.id
) // )
templateApi(state.hierarchy).addField(state.currentNode, field) // templateApi(state.hierarchy).addField(state.currentNode, field)
return state // return state
}) // })
} // }
export const deleteField = store => field => { // export const deleteField = store => field => {
store.update(state => { // store.update(state => {
state.currentNode.fields = state.currentNode.fields.filter( // state.currentNode.fields = state.currentNode.fields.filter(
f => f.name !== field.name // f => f.name !== field.name
) // )
return state // return state
}) // })
} // }
const incrementAccessLevelsVersion = state => { const incrementAccessLevelsVersion = state => {
state.accessLevels.version = state.accessLevels.version state.accessLevels.version = state.accessLevels.version

View file

@ -43,22 +43,14 @@ export const getStore = () => {
libraries: null, libraries: null,
showSettings: false, showSettings: false,
useAnalytics: true, useAnalytics: true,
neoAppId: "84a14e3065c5f15ef8410a5e4c000d68" appId: "",
clientId: "budibase"
} }
const store = writable(initial) const store = writable(initial)
store.setPackage = setPackage(store, initial) store.setPackage = setPackage(store, initial)
store.newChildModel = backendStoreActions.newModel(store, false)
store.newRootModel = backendStoreActions.newModel(store, true)
store.selectExistingNode = backendStoreActions.selectExistingNode(store)
store.newChildIndex = backendStoreActions.newIndex(store, false)
store.newRootIndex = backendStoreActions.newIndex(store, true)
store.saveCurrentNode = backendStoreActions.saveCurrentNode(store)
store.deleteCurrentNode = backendStoreActions.deleteCurrentNode(store)
store.saveField = backendStoreActions.saveField(store)
store.deleteField = backendStoreActions.deleteField(store)
store.saveLevel = backendStoreActions.saveLevel(store) store.saveLevel = backendStoreActions.saveLevel(store)
store.deleteLevel = backendStoreActions.deleteLevel(store) store.deleteLevel = backendStoreActions.deleteLevel(store)
store.createDatabaseForApp = backendStoreActions.createDatabaseForApp(store) store.createDatabaseForApp = backendStoreActions.createDatabaseForApp(store)
@ -102,9 +94,9 @@ export default getStore
const setPackage = (store, initial) => async (pkg) => { const setPackage = (store, initial) => async (pkg) => {
const [main_screens, unauth_screens] = await Promise.all([ const [main_screens, unauth_screens] = await Promise.all([
api.get(`/_builder/api/${pkg.application.name}/pages/main/screens`).then(r => r.json()), api.get(`/_builder/api/${pkg.application._id}/pages/main/screens`).then(r => r.json()),
api api
.get(`/_builder/api/${pkg.application.name}/pages/unauthenticated/screens`) .get(`/_builder/api/${pkg.application._id}/pages/unauthenticated/screens`)
.then(r => r.json()), .then(r => r.json()),
]) ])
@ -119,12 +111,13 @@ const setPackage = (store, initial) => async (pkg) => {
}, },
} }
initial.libraries = await loadLibs(pkg.application.name, pkg) initial.libraries = await loadLibs(pkg.application._id, pkg)
initial.loadLibraryUrls = pageName => { initial.loadLibraryUrls = pageName => {
const libs = libUrlsForPreview(pkg, pageName) const libs = libUrlsForPreview(pkg, pageName)
return libs return libs
} }
initial.appname = pkg.application.name initial.appname = pkg.application.name
initial.appId = pkg.application._id
initial.pages = pkg.pages initial.pages = pkg.pages
initial.hasAppPackage = true initial.hasAppPackage = true
initial.hierarchy = pkg.appDefinition.hierarchy initial.hierarchy = pkg.appDefinition.hierarchy
@ -138,15 +131,7 @@ const setPackage = (store, initial) => async (pkg) => {
initial.actions = values(pkg.appDefinition.actions) initial.actions = values(pkg.appDefinition.actions)
initial.triggers = pkg.appDefinition.triggers initial.triggers = pkg.appDefinition.triggers
initial.appInstances = pkg.application.instances initial.appInstances = pkg.application.instances
initial.appId = pkg.application.id initial.appId = pkg.application._id
if (!!initial.hierarchy && !isEmpty(initial.hierarchy)) {
initial.hierarchy = constructHierarchy(initial.hierarchy)
const shadowHierarchy = createShadowHierarchy(initial.hierarchy)
if (initial.currentNode !== null) {
initial.currentNode = getNode(shadowHierarchy, initial.currentNode.nodeId)
}
}
store.set(initial) store.set(initial)
return initial return initial
@ -180,9 +165,6 @@ const importAppDefinition = store => appDefinition => {
}) })
} }
const createShadowHierarchy = hierarchy =>
constructHierarchy(JSON.parse(JSON.stringify(hierarchy)))
const saveScreen = store => screen => { const saveScreen = store => screen => {
store.update(s => { store.update(s => {
return _saveScreen(store, s, screen) return _saveScreen(store, s, screen)
@ -194,7 +176,7 @@ const _saveScreen = async (store, s, screen) => {
await api await api
.post( .post(
`/_builder/api/${s.appname}/pages/${s.currentPageName}/screen`, `/_builder/api/${s.appId}/pages/${s.currentPageName}/screen`,
screen screen
) )
.then(() => { .then(() => {
@ -227,7 +209,7 @@ const _saveScreen = async (store, s, screen) => {
const _saveScreenApi = (screen, s) => const _saveScreenApi = (screen, s) =>
api api
.post( .post(
`/_builder/api/${s.appname}/pages/${s.currentPageName}/screen`, `/_builder/api/${s.appId}/pages/${s.currentPageName}/screen`,
screen screen
) )
.then(() => _savePage(s)) .then(() => _savePage(s))
@ -277,7 +259,7 @@ const createGeneratedComponents = store => components => {
const doCreate = async () => { const doCreate = async () => {
for (let c of components) { for (let c of components) {
await api.post(`/_builder/api/${s.appname}/screen`, c) await api.post(`/_builder/api/${s.appId}/screen`, c)
} }
await _savePage(s) await _savePage(s)
@ -302,7 +284,7 @@ const deleteScreen = store => name => {
s.currentFrontEndType = "" s.currentFrontEndType = ""
} }
api.delete(`/_builder/api/${s.appname}/screen/${name}`) api.delete(`/_builder/api/${s.appId}/screen/${name}`)
return s return s
}) })
@ -330,12 +312,12 @@ const renameScreen = store => (oldname, newname) => {
const saveAllChanged = async () => { const saveAllChanged = async () => {
for (let screenName of changedScreens) { for (let screenName of changedScreens) {
const changedScreen = getExactComponent(screens, screenName) const changedScreen = getExactComponent(screens, screenName)
await api.post(`/_builder/api/${s.appname}/screen`, changedScreen) await api.post(`/_builder/api/${s.appId}/screen`, changedScreen)
} }
} }
api api
.patch(`/_builder/api/${s.appname}/screen`, { .patch(`/_builder/api/${s.appId}/screen`, {
oldname, oldname,
newname, newname,
}) })
@ -362,7 +344,7 @@ const savePage = store => async page => {
const addComponentLibrary = store => async lib => { const addComponentLibrary = store => async lib => {
const response = await api.get( const response = await api.get(
`/_builder/api/${s.appname}/componentlibrary?lib=${encodeURI(lib)}`, `/_builder/api/${s.appId}/componentlibrary?lib=${encodeURI(lib)}`,
undefined, undefined,
false false
) )
@ -419,7 +401,7 @@ const removeStylesheet = store => stylesheet => {
const _savePage = async s => { const _savePage = async s => {
const page = s.pages[s.currentPageName] const page = s.pages[s.currentPageName]
await api.post(`/_builder/api/${s.appname}/pages/${s.currentPageName}`, { await api.post(`/_builder/api/${s.appId}/pages/${s.currentPageName}`, {
page: { componentLibraries: s.pages.componentLibraries, ...page }, page: { componentLibraries: s.pages.componentLibraries, ...page },
uiFunctions: s.currentPageFunctions, uiFunctions: s.currentPageFunctions,
screens: page._screens, screens: page._screens,

View file

@ -1,16 +1,17 @@
import api from "builderStore/api" import api from "builderStore/api"
import { getNewRecord, getNewInstance } from "components/common/core"
export async function createUser(password, user, { appname, instanceId }) { export async function createUser(user, instanceId) {
const CREATE_USER_URL = `/_builder/instance/${appname}/${instanceId}/api/createUser` const CREATE_USER_URL = `/api/${instanceId}/users`
const response = await api.post(CREATE_USER_URL, { user, password }) const response = await api.post(CREATE_USER_URL, user)
return await response.json() const json = await response.json()
return json.user;
} }
export async function createDatabase(appname, instanceName) { export async function createDatabase(clientId, appname, instanceName) {
const CREATE_DATABASE_URL = `/_builder/instance/_master/0/api/record/` const CREATE_DATABASE_URL = `/api/${clientId}/${appname}/instances`
const database = getNewInstance(appname, instanceName) const response = await api.post(CREATE_DATABASE_URL, {
const response = await api.post(CREATE_DATABASE_URL, database) name: instanceName
})
return await response.json() return await response.json()
} }

View file

@ -9,8 +9,8 @@
let databaseName let databaseName
async function createDatabase() { async function createDatabase() {
const response = await api.createDatabase($store.appId, databaseName) const response = await api.createDatabase($store.clientId, $store.appId, databaseName)
store.createDatabaseForApp(response) store.createDatabaseForApp(response.instance)
onClosed() onClosed()
} }
</script> </script>

View file

@ -7,23 +7,15 @@
let username let username
let password let password
let accessLevels = []
$: valid = username && password && accessLevels.length $: valid = username && password
$: currentAppInfo = { $: instanceId = $backendUiStore.selectedDatabase.id
appname: $store.appname,
instanceId: $backendUiStore.selectedDatabase.id,
}
async function createUser() { async function createUser() {
const user = { const user = { name: username, username, password }
name: username, const response = await api.createUser(user, instanceId);
accessLevels, console.log(response);
enabled: true, backendUiStore.actions.users.create(response)
temporaryAccessId: "",
}
const response = await api.createUser(password, user, currentAppInfo)
backendUiStore.actions.users.save(user)
onClosed() onClosed()
} }
</script> </script>
@ -35,11 +27,6 @@
<label class="uk-form-label" for="form-stacked-text">Password</label> <label class="uk-form-label" for="form-stacked-text">Password</label>
<input class="uk-input" type="password" bind:value={password} /> <input class="uk-input" type="password" bind:value={password} />
<label class="uk-form-label" for="form-stacked-text">Access Levels</label> <label class="uk-form-label" for="form-stacked-text">Access Levels</label>
<select multiple bind:value={accessLevels}>
{#each $store.accessLevels.levels as level}
<option value={level.name}>{level.name}</option>
{/each}
</select>
</div> </div>
<footer> <footer>
<ActionButton alert on:click={onClosed}>Cancel</ActionButton> <ActionButton alert on:click={onClosed}>Cancel</ActionButton>

View file

@ -13,7 +13,7 @@
} }
async function deleteDatabase(database) { async function deleteDatabase(database) {
const DELETE_DATABASE_URL = `/api/instances/${database.id}` const DELETE_DATABASE_URL = `/api/instances/${database.name}`
const response = await api.delete(DELETE_DATABASE_URL) const response = await api.delete(DELETE_DATABASE_URL)
store.update(state => { store.update(state => {
state.appInstances = state.appInstances.filter( state.appInstances = state.appInstances.filter(

View file

@ -10,8 +10,6 @@
return { name, props } return { name, props }
} }
let users = []
$: currentAppInfo = { $: currentAppInfo = {
appname: $store.appname, appname: $store.appname,
instanceId: $backendUiStore.selectedDatabase.id, instanceId: $backendUiStore.selectedDatabase.id,
@ -20,7 +18,7 @@
async function fetchUsers() { async function fetchUsers() {
const FETCH_USERS_URL = `/api/${currentAppInfo.instanceId}/users` const FETCH_USERS_URL = `/api/${currentAppInfo.instanceId}/users`
const response = await api.get(FETCH_USERS_URL) const response = await api.get(FETCH_USERS_URL)
users = await response.json() const users = await response.json()
backendUiStore.update(state => { backendUiStore.update(state => {
state.users = users state.users = users
return state return state
@ -32,7 +30,7 @@
<div class="root"> <div class="root">
<ul> <ul>
{#each users as user} {#each $backendUiStore.users as user}
<li> <li>
<i class="ri-user-4-line" /> <i class="ri-user-4-line" />
<button class:active={user.id === $store.currentUserId}> <button class:active={user.id === $store.currentUserId}>

View file

@ -13,7 +13,7 @@
<div> <div>
<h4 style="margin-bottom: 20px">Choose an Application</h4> <h4 style="margin-bottom: 20px">Choose an Application</h4>
{#each apps as app} {#each apps as app}
<a href={`/_builder/${app.name}`} class="app-link">{app.name}</a> <a href={`/_builder/${app._id}`} class="app-link">{app.name}</a>
{/each} {/each}
</div> </div>
</div> </div>

View file

@ -13,7 +13,7 @@
let promise = getPackage() let promise = getPackage()
async function getPackage() { async function getPackage() {
const res = await fetch(`/api/budibase/${$store.neoAppId}/appPackage`) const res = await fetch(`/api/${$store.clientId}/${application}/appPackage`)
const pkg = await res.json() const pkg = await res.json()
if (res.ok) { if (res.ok) {

View file

@ -1,4 +1,5 @@
<script> <script>
import { store } from "builderStore";
import AppList from "components/start/AppList.svelte" import AppList from "components/start/AppList.svelte"
import { onMount } from "svelte" import { onMount } from "svelte"
import IconButton from "components/common/IconButton.svelte" import IconButton from "components/common/IconButton.svelte"
@ -7,7 +8,7 @@
let promise = getApps() let promise = getApps()
async function getApps() { async function getApps() {
const res = await fetch(`/api/budibase/applications`) const res = await fetch(`/api/${$store.clientId}/applications`)
const json = await res.json() const json = await res.json()
if (res.ok) { if (res.ok) {

View file

@ -1,43 +1,6 @@
node_modules/
# Logs myapps/
logs config.js
*.log /builder/*
!/builder/assets/
# Runtime data public/
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
.eslintcache
# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules
node_modules_ubuntu
node_modules_windows
# OSX
.DS_Store
# flow-typed
flow-typed/npm/*
!flow-typed/npm/module_vx.x.x.js
.idea
npm-debug.log.*
dist

View file

@ -1,22 +0,0 @@
MIT License
-----------
Copyright (C) 2010-2014 Philipp Dunkel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View file

@ -1,78 +0,0 @@
# fsevents [![NPM](https://nodei.co/npm/fsevents.png)](https://nodei.co/npm/fsevents/)
Native access to OS X FSEvents in [Node.js](http://nodejs.org/)
The FSEvents API in OS X allows applications to register for notifications of
changes to a given directory tree. It is a very fast and lightweight alternative
to kqueue.
This is a low-level library. For a cross-compatible file watching module that
uses fsevents, check out [Chokidar](https://www.npmjs.com/package/chokidar).
* [Module Site & GitHub](https://github.com/strongloop/fsevents)
* [NPM Page](https://npmjs.org/package/fsevents)
## Installation
$ npm install fsevents
## Usage
```js
var fsevents = require('fsevents');
var watcher = fsevents(__dirname);
watcher.on('fsevent', function(path, flags, id) { }); // RAW Event as emitted by OS-X
watcher.on('change', function(path, info) { }); // Common Event for all changes
watcher.start() // To start observation
watcher.stop() // To end observation
```
### Events
* *fsevent* - RAW Event as emitted by OS-X
* *change* - Common Event for all changes
* *created* - A File-System-Item has been created
* *deleted* - A File-System-Item has been deleted
* *modified* - A File-System-Item has been modified
* *moved-out* - A File-System-Item has been moved away from this location
* *moved-in* - A File-System-Item has been moved into this location
All events except *fsevent* take an *info* object as the second parameter of the callback. The structure of this object is:
```js
{
"event": "<event-type>",
"id": <eventi-id>,
"path": "<path-that-this-is-about>",
"type": "<file|directory|symlink>",
"changes": {
"inode": true, // Has the iNode Meta-Information changed
"finder": false, // Has the Finder Meta-Data changed
"access": false, // Have the access permissions changed
"xattrs": false // Have the xAttributes changed
},
"flags": <raw-flags>
}
```
## MIT License
Copyright (C) 2010-2014 Philipp Dunkel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View file

@ -1,106 +0,0 @@
/*
** © 2014 by Philipp Dunkel <pip@pipobscure.com>
** Licensed under MIT License.
*/
/* jshint node:true */
'use strict';
if (process.platform !== 'darwin')
throw new Error('Module \'fsevents\' is not compatible with platform \'' + process.platform + '\'');
var Native = require("bindings")("fse");
var EventEmitter = require('events').EventEmitter;
var fs = require('fs');
var inherits = require('util').inherits;
function FSEvents(path, handler) {
EventEmitter.call(this);
Object.defineProperty(this, '_impl', {
value: new Native.FSEvents(String(path || ''), handler),
enumerable: false,
writable: false
});
}
inherits(FSEvents, EventEmitter);
proxies(FSEvents, Native.FSEvents);
module.exports = watch;
module.exports.getInfo = getInfo;
module.exports.FSEvents = Native.FSEvents;
module.exports.Constants = Native.Constants;
var defer = global.setImmediate || process.nextTick;
function watch(path) {
var fse = new FSEvents(String(path || ''), handler);
EventEmitter.call(fse);
return fse;
function handler(path, flags, id) {
defer(function() {
fse.emit('fsevent', path, flags, id);
var info = getInfo(path, flags);
info.id = id;
if (info.event === 'moved') {
fs.stat(info.path, function(err, stat) {
info.event = (err || !stat) ? 'moved-out' : 'moved-in';
fse.emit('change', path, info);
fse.emit(info.event, path, info);
});
} else {
fse.emit('change', path, info);
fse.emit(info.event, path, info);
}
});
}
}
function proxies(ctor, target) {
Object.keys(target.prototype).filter(function(key) {
return typeof target.prototype[key] === 'function';
}).forEach(function(key) {
ctor.prototype[key] = function() {
this._impl[key].apply(this._impl, arguments);
return this;
}
});
}
function getFileType(flags) {
if (Native.Constants.kFSEventStreamEventFlagItemIsFile & flags) return 'file';
if (Native.Constants.kFSEventStreamEventFlagItemIsDir & flags) return 'directory';
if (Native.Constants.kFSEventStreamEventFlagItemIsSymlink & flags) return 'symlink';
}
function getEventType(flags) {
if (Native.Constants.kFSEventStreamEventFlagItemRemoved & flags) return 'deleted';
if (Native.Constants.kFSEventStreamEventFlagItemRenamed & flags) return 'moved';
if (Native.Constants.kFSEventStreamEventFlagItemCreated & flags) return 'created';
if (Native.Constants.kFSEventStreamEventFlagItemModified & flags) return 'modified';
if (Native.Constants.kFSEventStreamEventFlagRootChanged & flags) return 'root-changed';
return 'unknown';
}
function getFileChanges(flags) {
return {
inode: !! (Native.Constants.kFSEventStreamEventFlagItemInodeMetaMod & flags),
finder: !! (Native.Constants.kFSEventStreamEventFlagItemFinderInfoMod & flags),
access: !! (Native.Constants.kFSEventStreamEventFlagItemChangeOwner & flags),
xattrs: !! (Native.Constants.kFSEventStreamEventFlagItemXattrMod & flags)
};
}
function getInfo(path, flags) {
return {
path: path,
event: getEventType(flags),
type: getFileType(flags),
changes: getFileChanges(flags),
flags: flags
};
}

View file

@ -1,36 +0,0 @@
{
"name": "fsevents",
"version": "1.2.12",
"description": "Native Access to Mac OS-X FSEvents",
"main": "fsevents.js",
"dependencies": {
"bindings": "^1.5.0",
"nan": "^2.12.1"
},
"os": [
"darwin"
],
"engines": {
"node": ">= 4.0"
},
"scripts": {
"test": "node ./test/fsevents.js && node ./test/function.js 2> /dev/null"
},
"repository": {
"type": "git",
"url": "https://github.com/strongloop/fsevents.git"
},
"keywords": [
"fsevents",
"mac"
],
"author": "Philipp Dunkel <pip@pipobscure.com>",
"license": "MIT",
"bugs": {
"url": "https://github.com/strongloop/fsevents/issues"
},
"bundledDependencies": [
"node-pre-gyp"
],
"homepage": "https://github.com/strongloop/fsevents"
}

Binary file not shown.

View file

@ -0,0 +1 @@
MANIFEST-000004

View file

View file

@ -0,0 +1,5 @@
2020/04/23-10:07:34.635926 70000d912000 Recovering log #3
2020/04/23-10:07:34.636067 70000d912000 Level-0 table #5: started
2020/04/23-10:07:34.636467 70000d912000 Level-0 table #5: 629 bytes OK
2020/04/23-10:07:34.637440 70000d912000 Delete type=0 #3
2020/04/23-10:07:34.637605 70000d912000 Delete type=3 #2

View file

@ -0,0 +1 @@
2020/04/23-10:07:12.630205 70000d6bd000 Delete type=3 #1

Binary file not shown.

View file

@ -0,0 +1 @@
MANIFEST-000002

View file

View file

@ -0,0 +1 @@
2020/04/23-10:07:12.642112 70000dec0000 Delete type=3 #1

Binary file not shown.

View file

@ -1,6 +1,11 @@
const nano = require("nano") // const nano = require("nano")
const PouchDB = require("pouchdb");
const COUCH_DB_URL = const COUCH_DB_URL =
process.env.COUCH_DB_URL || "http://admin:password@localhost:5984" process.env.COUCH_DB_URL || "http://admin:password@localhost:5984"
module.exports = nano(COUCH_DB_URL) const CouchDB = PouchDB.defaults({
prefix: COUCH_DB_URL
});
module.exports = CouchDB;

View file

@ -0,0 +1,15 @@
const jwt = require("jsonwebtoken");
module.exports = async (ctx, next) => {
if (!ctx.headers.authorization) ctx.throw(403, "No token provided");
const [_, token] = ctx.headers.authorization.split(" ");
try {
ctx.request.jwtPayload = jwt.verify(token, ctx.config.jwtSecret);
} catch (err) {
ctx.throw(err.status || 403, err.text);
}
await next();
};

View file

@ -1,11 +1,11 @@
const couchdb = require("../../db"); const CouchDB = require("../../db");
const { const {
getPackageForBuilder, getPackageForBuilder,
} = require("../../utilities/builder") } = require("../../utilities/builder")
exports.fetch = async function(ctx) { exports.fetch = async function(ctx) {
const clientDb = couchdb.db.use(`client-${ctx.params.clientId}`); const clientDb = new CouchDB(`client-${ctx.params.clientId}`);
const body = await clientDb.view("client", "by_type", { const body = await clientDb.query("client/by_type", {
include_docs: true, include_docs: true,
key: ["app"] key: ["app"]
}); });
@ -14,14 +14,14 @@ exports.fetch = async function(ctx) {
}; };
exports.fetchAppPackage = async function(ctx) { exports.fetchAppPackage = async function(ctx) {
const clientDb = couchdb.db.use(`client-${ctx.params.clientId}`); const clientDb = new CouchDB(`client-${ctx.params.clientId}`);
const application = await clientDb.get(ctx.params.applicationId); const application = await clientDb.get(ctx.params.applicationId);
ctx.body = await getPackageForBuilder(ctx.config, application); ctx.body = await getPackageForBuilder(ctx.config, application);
} }
exports.create = async function(ctx) { exports.create = async function(ctx) {
const clientDb = couchdb.db.use(`client-${ctx.params.clientId}`); const clientDb = new CouchDB(`client-${ctx.params.clientId}`);
const { id, rev } = await clientDb.insert({ const { id, rev } = await clientDb.post({
type: "app", type: "app",
instances: [], instances: [],
...ctx.request.body, ...ctx.request.body,

View file

@ -1,30 +1,41 @@
const couchdb = require("../../db"); const jwt = require("jsonwebtoken");
const CouchDB = require("../../db");
const bcrypt = require("../../utilities/bcrypt");
const controller = { exports.forgotPassword = async ctx => {
forgotPassword: async ctx => { };
}, exports.setPassword = async ctx => { };
setPassword: async ctx => {
}, exports.changePassword = async ctx => {
changePassword: async ctx => { };
},
authenticate: async ctx => {
// const user = await ctx.master.authenticate(
// ctx.sessionId,
// ctx.params.appname,
// ctx.request.body.username,
// ctx.request.body.password
// )
// if (!user) { exports.authenticate = async ctx => {
// ctx.throw(StatusCodes.UNAUTHORIZED, "invalid username or password") const { username, password } = ctx.request.body;
// }
// ctx.body = user.user_json if (!username) ctx.throw(400, "Username Required.");
// ctx.response.status = StatusCodes.OK if (!password) ctx.throw(400, "Password Required");
// query couch for their username
const db = new CouchDB(ctx.params.instanceId);
const dbUser = await db.query("database/by_username", {
include_docs: true,
key: username
});
if (await bcrypt.compare(password, dbUser.password)) {
const payload = {
userId: dbUser._id,
accessLevel: "",
instanceId: ctx.params.instanceId
};
const token = jwt.sign(payload, ctx.config.secret, {
expiresIn: "1 day"
});
ctx.body = token;
} else {
ctx.throw(401, "Invalid credentials.");
} }
} }
module.exports = controller;

View file

@ -1,10 +1,11 @@
const couchdb = require("../../db"); const CouchDB = require("../../db");
exports.create = async function(ctx) { exports.create = async function(ctx) {
const clientId = `client-${ctx.request.body.clientId}`; const clientId = `client-${ctx.request.body.clientId}`;
await couchdb.db.create(clientId); const db = new CouchDB(clientId);
await couchdb.db.use(clientId).insert({ await db.put({
_id: "_design/client",
views: { views: {
by_type: { by_type: {
map: function(doc) { map: function(doc) {
@ -12,7 +13,7 @@ exports.create = async function(ctx) {
} }
} }
} }
}, '_design/client'); });
ctx.body = { ctx.body = {
message: `Client Database ${clientId} successfully provisioned.` message: `Client Database ${clientId} successfully provisioned.`
@ -22,7 +23,7 @@ exports.create = async function(ctx) {
exports.destroy = async function(ctx) { exports.destroy = async function(ctx) {
const dbId = `client-${ctx.params.clientId}`; const dbId = `client-${ctx.params.clientId}`;
await couchdb.db.destroy(dbId); await new CouchDB(dbId).destroy();
ctx.body = { ctx.body = {
status: 200, status: 200,

View file

@ -1,11 +1,13 @@
const couchdb = require("../../db"); const CouchDB = require("../../db");
exports.create = async function(ctx) { exports.create = async function(ctx) {
const instanceName = ctx.request.body.name; const instanceName = ctx.request.body.name;
await couchdb.db.create(instanceName); // await couchdb.db.create(instanceName);
const { clientId, applicationId } = ctx.params; const { clientId, applicationId } = ctx.params;
await couchdb.db.use(instanceName).insert({ const db = new CouchDB(instanceName);
await db.put({
_id: "_design/database",
metadata: { metadata: {
clientId, clientId,
applicationId applicationId
@ -17,35 +19,34 @@ exports.create = async function(ctx) {
} }
} }
} }
}, '_design/database'); });
// Add the new instance under the app clientDB // Add the new instance under the app clientDB
const clientDatabaseId = `client-${clientId}` const clientDatabaseId = `client-${clientId}`
const clientDb = await couchdb.db.use(clientDatabaseId); const clientDb = new CouchDB(clientDatabaseId);
const budibaseApp = await clientDb.get(applicationId); const budibaseApp = await clientDb.get(applicationId);
budibaseApp.instances.push({ const instance = { id: instanceName, name: instanceName };
id: instanceName, budibaseApp.instances.push(instance);
name: instanceName await clientDb.put(budibaseApp);
});
await clientDb.insert(budibaseApp, budibaseApp._id);
ctx.body = { ctx.body = {
message: `Instance Database ${instanceName} successfully provisioned.`, message: `Instance Database ${instanceName} successfully provisioned.`,
status: 200 status: 200,
instance
} }
}; };
exports.destroy = async function(ctx) { exports.destroy = async function(ctx) {
const db = couchdb.db.use(ctx.params.instanceId); const db = new CouchDB(ctx.params.instanceId);
const designDoc = await db.get("_design/database"); const designDoc = await db.get("_design/database");
await couchdb.db.destroy(ctx.params.instanceId) await db.destroy();
// remove instance from client application document // remove instance from client application document
const { metadata } = designDoc; const { metadata } = designDoc;
const clientDb = await couchdb.db.use(metadata.clientId); const clientDb = new CouchDB(metadata.clientId);
const budibaseApp = await clientDb.get(metadata.applicationId); const budibaseApp = await clientDb.get(metadata.applicationId);
budibaseApp.instances = budibaseApp.instances.filter(instance => instance !== ctx.params.instanceId); budibaseApp.instances = budibaseApp.instances.filter(instance => instance !== ctx.params.instanceId);
await clientDb.insert(budibaseApp, budibaseApp._id); await clientDb.put(budibaseApp);
ctx.body = { ctx.body = {
message: `Instance Database ${ctx.params.instanceId} successfully destroyed.`, message: `Instance Database ${ctx.params.instanceId} successfully destroyed.`,

View file

@ -1,8 +1,8 @@
const couchdb = require("../../db"); const CouchDB = require("../../db");
exports.fetch = async function(ctx) { exports.fetch = async function(ctx) {
const db = couchdb.db.use(ctx.params.instanceId); const db = new CouchDB(ctx.params.instanceId);
const body = await db.view("database", "by_type", { const body = await db.query("database/by_type", {
include_docs: true, include_docs: true,
key: ["model"] key: ["model"]
}); });
@ -10,8 +10,8 @@ exports.fetch = async function(ctx) {
} }
exports.create = async function(ctx) { exports.create = async function(ctx) {
const db = couchdb.db.use(ctx.params.instanceId); const db = new CouchDB(ctx.params.instanceId);
const newModel = await db.insert({ const newModel = await db.post({
type: "model", type: "model",
...ctx.request.body ...ctx.request.body
}); });
@ -27,7 +27,7 @@ exports.create = async function(ctx) {
}` }`
} }
}; };
await db.insert(designDoc, designDoc._id); await db.put(designDoc);
ctx.body = { ctx.body = {
message: `Model ${ctx.request.body.name} created successfully.`, message: `Model ${ctx.request.body.name} created successfully.`,
@ -44,21 +44,21 @@ exports.update = async function(ctx) {
} }
exports.destroy = async function(ctx) { exports.destroy = async function(ctx) {
const db = couchdb.db.use(ctx.params.instanceId) const db = new CouchDB(ctx.params.instanceId)
const model = await db.destroy(ctx.params.modelId, ctx.params.revId); const model = await db.remove(ctx.params.modelId, ctx.params.revId);
const modelViewId = `all_${model.id}` const modelViewId = `all_${model.id}`
// Delete all records for that model // Delete all records for that model
const records = await db.view("database", modelViewId); const records = await db.query(`database/${modelViewId}`);
await db.bulk({ await db.bulkDocs(
docs: records.rows.map(record => ({ id: record.id, _deleted: true })) records.rows.map(record => ({ id: record.id, _deleted: true }))
}); );
// delete the "all" view // delete the "all" view
const designDoc = await db.get("_design/database"); const designDoc = await db.get("_design/database");
delete designDoc.views[modelViewId]; delete designDoc.views[modelViewId];
await db.insert(designDoc, designDoc._id); await db.put(designDoc);
ctx.body = { ctx.body = {
message: `Model ${model.id} deleted.`, message: `Model ${model.id} deleted.`,

View file

@ -2,10 +2,10 @@ const couchdb = require("../../db")
const { const {
events, events,
schemaValidator schemaValidator
} = require("@budibase/common") } = require("../../../common");
exports.save = async function(ctx) { exports.save = async function(ctx) {
const db = couchdb.db.use(ctx.params.instanceId); const db = new CouchDB(ctx.params.instanceId);
const record = ctx.request.body; const record = ctx.request.body;
// validation with ajv // validation with ajv
@ -27,7 +27,7 @@ exports.save = async function(ctx) {
const existingRecord = record._id && await db.get(record._id); const existingRecord = record._id && await db.get(record._id);
if (existingRecord) { if (existingRecord) {
const response = await db.insert(record, existingRecord._id) const response = await db.put({ ...record, _id: existingRecord._id });
ctx.body = { ctx.body = {
message: "Record updated successfully.", message: "Record updated successfully.",
status: 200, status: 200,
@ -36,7 +36,7 @@ exports.save = async function(ctx) {
return; return;
} }
const response = await db.insert({ const response = await db.post({
modelId: ctx.params.modelId, modelId: ctx.params.modelId,
type: "record", type: "record",
...record ...record
@ -54,10 +54,9 @@ exports.save = async function(ctx) {
} }
exports.fetch = async function(ctx) { exports.fetch = async function(ctx) {
const db = couchdb.db.use(ctx.params.instanceId) const db = new CouchDB(ctx.params.instanceId)
const response = await db.view( const response = await db.query(
"database", `database/${ctx.params.viewName}`,
ctx.params.viewName,
{ {
include_docs: true include_docs: true
} }
@ -76,6 +75,6 @@ exports.find = async function(ctx) {
exports.destroy = async function(ctx) { exports.destroy = async function(ctx) {
const databaseId = ctx.params.instanceId; const databaseId = ctx.params.instanceId;
const db = couchdb.db.use(databaseId) const db = new CouchDB(databaseId)
ctx.body = await db.destroy(ctx.params.recordId, ctx.params.revId); ctx.body = await db.destroy(ctx.params.recordId, ctx.params.revId);
}; };

View file

@ -1,8 +1,9 @@
const couchdb = require("../../db"); const CouchDB = require("../../db");
const bcrypt = require("../../utilities/bcrypt");
exports.fetch = async function(ctx) { exports.fetch = async function(ctx) {
const database = couchdb.db.use(ctx.params.instanceId); const database = new CouchDB(ctx.params.instanceId);
const data = await database.view("database", "by_type", { const data = await database.query("database/by_type", {
include_docs: true, include_docs: true,
key: ["user"] key: ["user"]
}); });
@ -11,20 +12,32 @@ exports.fetch = async function(ctx) {
}; };
exports.create = async function(ctx) { exports.create = async function(ctx) {
const database = couchdb.db.use(ctx.params.instanceId); const database = new CouchDB(ctx.params.instanceId);
const response = await database.insert({ const { username, password, name } = ctx.request.body;
...ctx.request.body,
if (!username || !password) ctx.throw(400, "Username and Password Required.");
const response = await database.post({
username,
password: await bcrypt.hash(password),
name,
type: "user" type: "user"
}); });
ctx.body = { ctx.body = {
...response, user: {
id: response.id,
rev: response.rev,
username,
name
},
message: `User created successfully.`, message: `User created successfully.`,
status: 200 status: 200
} }
}; };
exports.destroy = async function(ctx) { exports.destroy = async function(ctx) {
const database = couchdb.db.use(ctx.params.instanceId); const database = new CouchDB(ctx.params.instanceId);
const response = await database.destroy(ctx.params.userId) const response = await database.destroy(ctx.params.userId)
ctx.body = { ctx.body = {
...response, ...response,

View file

@ -1,13 +1,13 @@
const couchdb = require("../../db"); const CouchDB = require("../../db");
const controller = { const controller = {
fetch: async ctx => { fetch: async ctx => {
const db = couchdb.db.use(ctx.params.instanceId); const db = new CouchDB(ctx.params.instanceId);
const designDoc = await db.get("_design/database"); const designDoc = await db.get("_design/database");
ctx.body = designDoc.views; ctx.body = designDoc.views;
}, },
create: async ctx => { create: async ctx => {
const db = couchdb.db.use(ctx.params.instanceId); const db = new CouchDB(ctx.params.instanceId);
const { name, ...viewDefinition } = ctx.request.body; const { name, ...viewDefinition } = ctx.request.body;
const designDoc = await db.get("_design/database"); const designDoc = await db.get("_design/database");
@ -15,7 +15,7 @@ const controller = {
...designDoc.views, ...designDoc.views,
[name]: viewDefinition [name]: viewDefinition
}; };
const newView = await db.insert(designDoc, designDoc._id); const newView = await db.put(designDoc);
ctx.body = { ctx.body = {
...newView, ...newView,
@ -24,8 +24,8 @@ const controller = {
} }
}, },
destroy: async ctx => { destroy: async ctx => {
const db = couchdb.db.use(ctx.params.instanceId); const db = new CouchDB(ctx.params.instanceId);
ctx.body = await database.destroy(ctx.params.userId) ctx.body = await db.destroy(ctx.params.userId)
} }
} }

View file

@ -14,13 +14,13 @@ router.get("/_builder/api/apps", async ctx => {
ctx.response.status = StatusCodes.OK ctx.response.status = StatusCodes.OK
}) })
router.get("/_builder/api/:appname/appPackage", async ctx => { // router.get("/_builder/api/:appname/appPackage", async ctx => {
const application = await ctx.master.getApplicationWithInstances( // const application = await ctx.master.getApplicationWithInstances(
ctx.params.appname // ctx.params.appname
) // )
ctx.body = await getPackageForBuilder(ctx.config, application) // ctx.body = await getPackageForBuilder(ctx.config, application)
ctx.response.status = StatusCodes.OK // ctx.response.status = StatusCodes.OK
}) // })
router router
.post("/_builder/api/:appname/backend", async ctx => { .post("/_builder/api/:appname/backend", async ctx => {

View file

@ -2,7 +2,6 @@ const supertest = require("supertest");
const app = require("../../../../app"); const app = require("../../../../app");
const { const {
createInstanceDatabase, createInstanceDatabase,
insertDocument,
destroyDatabase destroyDatabase
} = require("./couchTestUtils"); } = require("./couchTestUtils");

View file

@ -19,10 +19,11 @@
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"dependencies": { "dependencies": {
"@budibase/client": "^0.0.32", "@budibase/client": "^0.0.32",
"@budibase/common": "0.0.32",
"@budibase/core": "^0.0.32", "@budibase/core": "^0.0.32",
"@koa/router": "^8.0.0", "@koa/router": "^8.0.0",
"bcryptjs": "^2.4.3",
"fs-extra": "^8.1.0", "fs-extra": "^8.1.0",
"jsonwebtoken": "^8.5.1",
"koa": "^2.7.0", "koa": "^2.7.0",
"koa-body": "^4.1.0", "koa-body": "^4.1.0",
"koa-logger": "^3.2.1", "koa-logger": "^3.2.1",
@ -30,7 +31,7 @@
"koa-session": "^5.12.0", "koa-session": "^5.12.0",
"koa-static": "^5.0.0", "koa-static": "^5.0.0",
"lodash": "^4.17.13", "lodash": "^4.17.13",
"nano": "^8.2.2", "pouchdb": "^7.2.1",
"squirrelly": "^7.5.0", "squirrelly": "^7.5.0",
"tar-fs": "^2.0.0", "tar-fs": "^2.0.0",
"uuid": "^3.3.2", "uuid": "^3.3.2",

View file

@ -0,0 +1,11 @@
const bcrypt = require("bcryptjs");
const SALT_ROUNDS = process.env.SALT_ROUNDS || 10;
exports.hash = async data => {
const salt = await bcrypt.genSalt(SALT_ROUNDS);
const result = await bcrypt.hash(data, salt);
return result;
};
exports.compare = async (data, encrypted) => await bcrypt.compare(data, encrypted);

View file

@ -28,7 +28,7 @@ const getAppDefinition = async appPath =>
await readJSON(`${appPath}/appDefinition.json`) await readJSON(`${appPath}/appDefinition.json`)
module.exports.getPackageForBuilder = async (config, application) => { module.exports.getPackageForBuilder = async (config, application) => {
const appPath = resolve(process.cwd(), config.latestPackagesFolder, application.name); const appPath = resolve(process.cwd(), config.latestPackagesFolder, application._id);
const pages = await getPages(appPath) const pages = await getPages(appPath)

View file

@ -336,6 +336,7 @@ module.exports = async context => {
const getApplicationWithInstances = async appname => { const getApplicationWithInstances = async appname => {
const app = cloneDeep(await getApplication(appname)) const app = cloneDeep(await getApplication(appname))
app.instances = await bb.indexApi.listItems( app.instances = await bb.indexApi.listItems(
`/applications/${app.id}/allinstances` `/applications/${app.id}/allinstances`
) )

File diff suppressed because it is too large Load diff