pouchDB integration, use app id instead of app name for keying app packages
This commit is contained in:
parent
1381cefc41
commit
c986bba0d8
|
@ -1,34 +1,34 @@
|
|||
import { flatten, values, uniq, map } from "lodash/fp"
|
||||
import { pipe } from "components/common/core"
|
||||
|
||||
export const loadLibs = async (appName, appPackage) => {
|
||||
export const loadLibs = async (appId, appPackage) => {
|
||||
const allLibraries = {}
|
||||
|
||||
for (let lib of libsFromPages(appPackage.pages)) {
|
||||
const libModule = await import(makeLibraryUrl(appName, lib))
|
||||
const libModule = await import(makeLibraryUrl(appId, lib))
|
||||
allLibraries[lib] = libModule
|
||||
}
|
||||
|
||||
return allLibraries
|
||||
}
|
||||
|
||||
export const loadLibUrls = (appName, appPackage) => {
|
||||
export const loadLibUrls = (appId, appPackage) => {
|
||||
const allLibraries = []
|
||||
for (let lib of libsFromPages(appPackage.pages)) {
|
||||
const libUrl = makeLibraryUrl(appName, lib)
|
||||
const libUrl = makeLibraryUrl(appId, lib)
|
||||
allLibraries.push({ libName: lib, importPath: libUrl })
|
||||
}
|
||||
|
||||
return allLibraries
|
||||
}
|
||||
|
||||
export const loadLib = async (appName, lib, allLibs) => {
|
||||
allLibs[lib] = await import(makeLibraryUrl(appName, lib))
|
||||
export const loadLib = async (appId, lib, allLibs) => {
|
||||
allLibs[lib] = await import(makeLibraryUrl(appId, lib))
|
||||
return allLibs
|
||||
}
|
||||
|
||||
export const makeLibraryUrl = (appName, lib) =>
|
||||
`/_builder/${appName}/componentlibrary?lib=${encodeURI(lib)}`
|
||||
export const makeLibraryUrl = (appId, lib) =>
|
||||
`/_builder/${appId}/componentlibrary?lib=${encodeURI(lib)}`
|
||||
|
||||
export const libsFromPages = pages =>
|
||||
pipe(pages, [values, map(p => p.componentLibraries), flatten, uniq])
|
||||
|
|
|
@ -1,15 +1,9 @@
|
|||
import { writable } from "svelte/store"
|
||||
import api from "../api"
|
||||
import { cloneDeep, sortBy, find, remove } from "lodash/fp"
|
||||
import { hierarchy as hierarchyFunctions } from "../../../../core/src"
|
||||
import { find } from "lodash/fp"
|
||||
import {
|
||||
getNode,
|
||||
validate,
|
||||
constructHierarchy,
|
||||
templateApi,
|
||||
isIndex,
|
||||
canDeleteIndex,
|
||||
canDeleteModel,
|
||||
} from "components/common/core"
|
||||
|
||||
export const getBackendUiStore = () => {
|
||||
|
@ -20,6 +14,7 @@ export const getBackendUiStore = () => {
|
|||
},
|
||||
breadcrumbs: [],
|
||||
models: [],
|
||||
users: [],
|
||||
selectedDatabase: {},
|
||||
selectedModel: {},
|
||||
}
|
||||
|
@ -103,38 +98,24 @@ export const saveBackend = async state => {
|
|||
},
|
||||
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) => () => {
|
||||
store.update(state => {
|
||||
state.currentNodeIsNew = true
|
||||
const shadowHierarchy = createShadowHierarchy(state.hierarchy)
|
||||
const parent = useRoot
|
||||
? shadowHierarchy
|
||||
: getNode(shadowHierarchy, state.currentNode.nodeId)
|
||||
state.errors = []
|
||||
state.currentNode = templateApi(shadowHierarchy).getNewModelTemplate(
|
||||
parent,
|
||||
"",
|
||||
true
|
||||
)
|
||||
return state
|
||||
})
|
||||
}
|
||||
// export const newModel = (store, useRoot) => () => {
|
||||
// store.update(state => {
|
||||
// state.currentNodeIsNew = true
|
||||
// const shadowHierarchy = createShadowHierarchy(state.hierarchy)
|
||||
// const parent = useRoot
|
||||
// ? shadowHierarchy
|
||||
// : getNode(shadowHierarchy, state.currentNode.nodeId)
|
||||
// state.errors = []
|
||||
// state.currentNode = templateApi(shadowHierarchy).getNewModelTemplate(
|
||||
// parent,
|
||||
// "",
|
||||
// true
|
||||
// )
|
||||
// return state
|
||||
// })
|
||||
// }
|
||||
|
||||
export const selectExistingNode = store => nodeId => {
|
||||
store.update(state => {
|
||||
|
@ -145,133 +126,133 @@ export const selectExistingNode = store => nodeId => {
|
|||
})
|
||||
}
|
||||
|
||||
export const newIndex = (store, useRoot) => () => {
|
||||
store.update(state => {
|
||||
state.shadowHierarchy = createShadowHierarchy(state.hierarchy)
|
||||
state.currentNodeIsNew = true
|
||||
state.errors = []
|
||||
const parent = useRoot
|
||||
? state.shadowHierarchy
|
||||
: getNode(state.shadowHierarchy, state.currentNode.nodeId)
|
||||
// export const newIndex = (store, useRoot) => () => {
|
||||
// store.update(state => {
|
||||
// state.shadowHierarchy = createShadowHierarchy(state.hierarchy)
|
||||
// state.currentNodeIsNew = true
|
||||
// state.errors = []
|
||||
// const parent = useRoot
|
||||
// ? state.shadowHierarchy
|
||||
// : getNode(state.shadowHierarchy, state.currentNode.nodeId)
|
||||
|
||||
state.currentNode = templateApi(state.shadowHierarchy).getNewIndexTemplate(
|
||||
parent
|
||||
)
|
||||
return state
|
||||
})
|
||||
}
|
||||
// state.currentNode = templateApi(state.shadowHierarchy).getNewIndexTemplate(
|
||||
// parent
|
||||
// )
|
||||
// return state
|
||||
// })
|
||||
// }
|
||||
|
||||
export const saveCurrentNode = store => () => {
|
||||
store.update(state => {
|
||||
const errors = validate.node(state.currentNode)
|
||||
state.errors = errors
|
||||
if (errors.length > 0) {
|
||||
return state
|
||||
}
|
||||
const parentNode = getNode(
|
||||
state.hierarchy,
|
||||
state.currentNode.parent().nodeId
|
||||
)
|
||||
// export const saveCurrentNode = store => () => {
|
||||
// store.update(state => {
|
||||
// const errors = validate.node(state.currentNode)
|
||||
// state.errors = errors
|
||||
// if (errors.length > 0) {
|
||||
// return state
|
||||
// }
|
||||
// const parentNode = getNode(
|
||||
// state.hierarchy,
|
||||
// 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
|
||||
if (existingNode) {
|
||||
// remove existing
|
||||
index = existingNode.parent().children.indexOf(existingNode)
|
||||
if (isIndex(existingNode)) {
|
||||
parentNode.indexes = parentNode.indexes.filter(
|
||||
node => node.nodeId !== existingNode.nodeId
|
||||
)
|
||||
} else {
|
||||
parentNode.children = parentNode.children.filter(
|
||||
node => node.nodeId !== existingNode.nodeId
|
||||
)
|
||||
}
|
||||
}
|
||||
// let index = parentNode.children.length
|
||||
// if (existingNode) {
|
||||
// // remove existing
|
||||
// index = existingNode.parent().children.indexOf(existingNode)
|
||||
// if (isIndex(existingNode)) {
|
||||
// parentNode.indexes = parentNode.indexes.filter(
|
||||
// node => node.nodeId !== existingNode.nodeId
|
||||
// )
|
||||
// } else {
|
||||
// parentNode.children = parentNode.children.filter(
|
||||
// node => node.nodeId !== existingNode.nodeId
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
|
||||
// should add node into existing hierarchy
|
||||
const cloned = cloneDeep(state.currentNode)
|
||||
templateApi(state.hierarchy).constructNode(parentNode, cloned)
|
||||
// // should add node into existing hierarchy
|
||||
// const cloned = cloneDeep(state.currentNode)
|
||||
// templateApi(state.hierarchy).constructNode(parentNode, cloned)
|
||||
|
||||
if (isIndex(existingNode)) {
|
||||
parentNode.children = sortBy("name", parentNode.children)
|
||||
} else {
|
||||
parentNode.indexes = sortBy("name", parentNode.indexes)
|
||||
}
|
||||
// if (isIndex(existingNode)) {
|
||||
// parentNode.children = sortBy("name", parentNode.children)
|
||||
// } else {
|
||||
// parentNode.indexes = sortBy("name", parentNode.indexes)
|
||||
// }
|
||||
|
||||
if (!existingNode && state.currentNode.type === "record") {
|
||||
const defaultIndex = templateApi(state.hierarchy).getNewIndexTemplate(
|
||||
cloned.parent()
|
||||
)
|
||||
defaultIndex.name = hierarchyFunctions.isTopLevelIndex(cloned)
|
||||
? `all_${cloned.name}s`
|
||||
: `${cloned.parent().name}_${cloned.name}s`
|
||||
// if (!existingNode && state.currentNode.type === "record") {
|
||||
// const defaultIndex = templateApi(state.hierarchy).getNewIndexTemplate(
|
||||
// cloned.parent()
|
||||
// )
|
||||
// defaultIndex.name = hierarchyFunctions.isTopLevelIndex(cloned)
|
||||
// ? `all_${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 => () => {
|
||||
store.update(state => {
|
||||
const nodeToDelete = getNode(state.hierarchy, state.currentNode.nodeId)
|
||||
state.currentNode = hierarchyFunctions.isRoot(nodeToDelete.parent())
|
||||
? state.hierarchy.children.find(node => node !== state.currentNode)
|
||||
: nodeToDelete.parent()
|
||||
// export const deleteCurrentNode = store => () => {
|
||||
// store.update(state => {
|
||||
// const nodeToDelete = getNode(state.hierarchy, state.currentNode.nodeId)
|
||||
// state.currentNode = hierarchyFunctions.isRoot(nodeToDelete.parent())
|
||||
// ? state.hierarchy.children.find(node => node !== state.currentNode)
|
||||
// : nodeToDelete.parent()
|
||||
|
||||
const isModel = hierarchyFunctions.isModel(nodeToDelete)
|
||||
// const isModel = hierarchyFunctions.isModel(nodeToDelete)
|
||||
|
||||
const check = isModel
|
||||
? canDeleteModel(nodeToDelete)
|
||||
: canDeleteIndex(nodeToDelete)
|
||||
// const check = isModel
|
||||
// ? canDeleteModel(nodeToDelete)
|
||||
// : canDeleteIndex(nodeToDelete)
|
||||
|
||||
if (!check.canDelete) {
|
||||
state.errors = check.errors.map(e => ({ error: e }))
|
||||
return state
|
||||
}
|
||||
// if (!check.canDelete) {
|
||||
// state.errors = check.errors.map(e => ({ error: e }))
|
||||
// return state
|
||||
// }
|
||||
|
||||
const recordOrIndexKey = isModel ? "children" : "indexes"
|
||||
// const recordOrIndexKey = isModel ? "children" : "indexes"
|
||||
|
||||
// remove the selected record or index
|
||||
const newCollection = remove(
|
||||
node => node.nodeId === nodeToDelete.nodeId,
|
||||
nodeToDelete.parent()[recordOrIndexKey]
|
||||
)
|
||||
// // remove the selected record or index
|
||||
// const newCollection = remove(
|
||||
// node => node.nodeId === nodeToDelete.nodeId,
|
||||
// nodeToDelete.parent()[recordOrIndexKey]
|
||||
// )
|
||||
|
||||
nodeToDelete.parent()[recordOrIndexKey] = newCollection
|
||||
// nodeToDelete.parent()[recordOrIndexKey] = newCollection
|
||||
|
||||
state.errors = []
|
||||
saveBackend(state)
|
||||
return state
|
||||
})
|
||||
}
|
||||
// state.errors = []
|
||||
// saveBackend(state)
|
||||
// return state
|
||||
// })
|
||||
// }
|
||||
|
||||
export const saveField = store => field => {
|
||||
store.update(state => {
|
||||
state.currentNode.fields = state.currentNode.fields.filter(
|
||||
f => f.id !== field.id
|
||||
)
|
||||
// export const saveField = store => field => {
|
||||
// store.update(state => {
|
||||
// state.currentNode.fields = state.currentNode.fields.filter(
|
||||
// f => f.id !== field.id
|
||||
// )
|
||||
|
||||
templateApi(state.hierarchy).addField(state.currentNode, field)
|
||||
return state
|
||||
})
|
||||
}
|
||||
// templateApi(state.hierarchy).addField(state.currentNode, field)
|
||||
// return state
|
||||
// })
|
||||
// }
|
||||
|
||||
export const deleteField = store => field => {
|
||||
store.update(state => {
|
||||
state.currentNode.fields = state.currentNode.fields.filter(
|
||||
f => f.name !== field.name
|
||||
)
|
||||
return state
|
||||
})
|
||||
}
|
||||
// export const deleteField = store => field => {
|
||||
// store.update(state => {
|
||||
// state.currentNode.fields = state.currentNode.fields.filter(
|
||||
// f => f.name !== field.name
|
||||
// )
|
||||
// return state
|
||||
// })
|
||||
// }
|
||||
|
||||
const incrementAccessLevelsVersion = state => {
|
||||
state.accessLevels.version = state.accessLevels.version
|
||||
|
|
|
@ -43,22 +43,14 @@ export const getStore = () => {
|
|||
libraries: null,
|
||||
showSettings: false,
|
||||
useAnalytics: true,
|
||||
neoAppId: "84a14e3065c5f15ef8410a5e4c000d68"
|
||||
appId: "",
|
||||
clientId: "budibase"
|
||||
}
|
||||
|
||||
const store = writable(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.deleteLevel = backendStoreActions.deleteLevel(store)
|
||||
store.createDatabaseForApp = backendStoreActions.createDatabaseForApp(store)
|
||||
|
@ -102,9 +94,9 @@ export default getStore
|
|||
const setPackage = (store, initial) => async (pkg) => {
|
||||
|
||||
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
|
||||
.get(`/_builder/api/${pkg.application.name}/pages/unauthenticated/screens`)
|
||||
.get(`/_builder/api/${pkg.application._id}/pages/unauthenticated/screens`)
|
||||
.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 => {
|
||||
const libs = libUrlsForPreview(pkg, pageName)
|
||||
return libs
|
||||
}
|
||||
initial.appname = pkg.application.name
|
||||
initial.appId = pkg.application._id
|
||||
initial.pages = pkg.pages
|
||||
initial.hasAppPackage = true
|
||||
initial.hierarchy = pkg.appDefinition.hierarchy
|
||||
|
@ -138,15 +131,7 @@ const setPackage = (store, initial) => async (pkg) => {
|
|||
initial.actions = values(pkg.appDefinition.actions)
|
||||
initial.triggers = pkg.appDefinition.triggers
|
||||
initial.appInstances = pkg.application.instances
|
||||
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)
|
||||
}
|
||||
}
|
||||
initial.appId = pkg.application._id
|
||||
|
||||
store.set(initial)
|
||||
return initial
|
||||
|
@ -180,9 +165,6 @@ const importAppDefinition = store => appDefinition => {
|
|||
})
|
||||
}
|
||||
|
||||
const createShadowHierarchy = hierarchy =>
|
||||
constructHierarchy(JSON.parse(JSON.stringify(hierarchy)))
|
||||
|
||||
const saveScreen = store => screen => {
|
||||
store.update(s => {
|
||||
return _saveScreen(store, s, screen)
|
||||
|
@ -194,7 +176,7 @@ const _saveScreen = async (store, s, screen) => {
|
|||
|
||||
await api
|
||||
.post(
|
||||
`/_builder/api/${s.appname}/pages/${s.currentPageName}/screen`,
|
||||
`/_builder/api/${s.appId}/pages/${s.currentPageName}/screen`,
|
||||
screen
|
||||
)
|
||||
.then(() => {
|
||||
|
@ -227,7 +209,7 @@ const _saveScreen = async (store, s, screen) => {
|
|||
const _saveScreenApi = (screen, s) =>
|
||||
api
|
||||
.post(
|
||||
`/_builder/api/${s.appname}/pages/${s.currentPageName}/screen`,
|
||||
`/_builder/api/${s.appId}/pages/${s.currentPageName}/screen`,
|
||||
screen
|
||||
)
|
||||
.then(() => _savePage(s))
|
||||
|
@ -277,7 +259,7 @@ const createGeneratedComponents = store => components => {
|
|||
|
||||
const doCreate = async () => {
|
||||
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)
|
||||
|
@ -302,7 +284,7 @@ const deleteScreen = store => name => {
|
|||
s.currentFrontEndType = ""
|
||||
}
|
||||
|
||||
api.delete(`/_builder/api/${s.appname}/screen/${name}`)
|
||||
api.delete(`/_builder/api/${s.appId}/screen/${name}`)
|
||||
|
||||
return s
|
||||
})
|
||||
|
@ -330,12 +312,12 @@ const renameScreen = store => (oldname, newname) => {
|
|||
const saveAllChanged = async () => {
|
||||
for (let screenName of changedScreens) {
|
||||
const changedScreen = getExactComponent(screens, screenName)
|
||||
await api.post(`/_builder/api/${s.appname}/screen`, changedScreen)
|
||||
await api.post(`/_builder/api/${s.appId}/screen`, changedScreen)
|
||||
}
|
||||
}
|
||||
|
||||
api
|
||||
.patch(`/_builder/api/${s.appname}/screen`, {
|
||||
.patch(`/_builder/api/${s.appId}/screen`, {
|
||||
oldname,
|
||||
newname,
|
||||
})
|
||||
|
@ -362,7 +344,7 @@ const savePage = store => async page => {
|
|||
|
||||
const addComponentLibrary = store => async lib => {
|
||||
const response = await api.get(
|
||||
`/_builder/api/${s.appname}/componentlibrary?lib=${encodeURI(lib)}`,
|
||||
`/_builder/api/${s.appId}/componentlibrary?lib=${encodeURI(lib)}`,
|
||||
undefined,
|
||||
false
|
||||
)
|
||||
|
@ -419,7 +401,7 @@ const removeStylesheet = store => stylesheet => {
|
|||
const _savePage = async s => {
|
||||
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 },
|
||||
uiFunctions: s.currentPageFunctions,
|
||||
screens: page._screens,
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
import api from "builderStore/api"
|
||||
import { getNewRecord, getNewInstance } from "components/common/core"
|
||||
|
||||
export async function createUser(password, user, { appname, instanceId }) {
|
||||
const CREATE_USER_URL = `/_builder/instance/${appname}/${instanceId}/api/createUser`
|
||||
const response = await api.post(CREATE_USER_URL, { user, password })
|
||||
return await response.json()
|
||||
export async function createUser(user, instanceId) {
|
||||
const CREATE_USER_URL = `/api/${instanceId}/users`
|
||||
const response = await api.post(CREATE_USER_URL, user)
|
||||
const json = await response.json()
|
||||
return json.user;
|
||||
}
|
||||
|
||||
export async function createDatabase(appname, instanceName) {
|
||||
const CREATE_DATABASE_URL = `/_builder/instance/_master/0/api/record/`
|
||||
const database = getNewInstance(appname, instanceName)
|
||||
const response = await api.post(CREATE_DATABASE_URL, database)
|
||||
export async function createDatabase(clientId, appname, instanceName) {
|
||||
const CREATE_DATABASE_URL = `/api/${clientId}/${appname}/instances`
|
||||
const response = await api.post(CREATE_DATABASE_URL, {
|
||||
name: instanceName
|
||||
})
|
||||
return await response.json()
|
||||
}
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
let databaseName
|
||||
|
||||
async function createDatabase() {
|
||||
const response = await api.createDatabase($store.appId, databaseName)
|
||||
store.createDatabaseForApp(response)
|
||||
const response = await api.createDatabase($store.clientId, $store.appId, databaseName)
|
||||
store.createDatabaseForApp(response.instance)
|
||||
onClosed()
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -7,23 +7,15 @@
|
|||
|
||||
let username
|
||||
let password
|
||||
let accessLevels = []
|
||||
|
||||
$: valid = username && password && accessLevels.length
|
||||
$: currentAppInfo = {
|
||||
appname: $store.appname,
|
||||
instanceId: $backendUiStore.selectedDatabase.id,
|
||||
}
|
||||
$: valid = username && password
|
||||
$: instanceId = $backendUiStore.selectedDatabase.id
|
||||
|
||||
async function createUser() {
|
||||
const user = {
|
||||
name: username,
|
||||
accessLevels,
|
||||
enabled: true,
|
||||
temporaryAccessId: "",
|
||||
}
|
||||
const response = await api.createUser(password, user, currentAppInfo)
|
||||
backendUiStore.actions.users.save(user)
|
||||
const user = { name: username, username, password }
|
||||
const response = await api.createUser(user, instanceId);
|
||||
console.log(response);
|
||||
backendUiStore.actions.users.create(response)
|
||||
onClosed()
|
||||
}
|
||||
</script>
|
||||
|
@ -35,11 +27,6 @@
|
|||
<label class="uk-form-label" for="form-stacked-text">Password</label>
|
||||
<input class="uk-input" type="password" bind:value={password} />
|
||||
<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>
|
||||
<footer>
|
||||
<ActionButton alert on:click={onClosed}>Cancel</ActionButton>
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
}
|
||||
|
||||
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)
|
||||
store.update(state => {
|
||||
state.appInstances = state.appInstances.filter(
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
return { name, props }
|
||||
}
|
||||
|
||||
let users = []
|
||||
|
||||
$: currentAppInfo = {
|
||||
appname: $store.appname,
|
||||
instanceId: $backendUiStore.selectedDatabase.id,
|
||||
|
@ -20,7 +18,7 @@
|
|||
async function fetchUsers() {
|
||||
const FETCH_USERS_URL = `/api/${currentAppInfo.instanceId}/users`
|
||||
const response = await api.get(FETCH_USERS_URL)
|
||||
users = await response.json()
|
||||
const users = await response.json()
|
||||
backendUiStore.update(state => {
|
||||
state.users = users
|
||||
return state
|
||||
|
@ -32,7 +30,7 @@
|
|||
|
||||
<div class="root">
|
||||
<ul>
|
||||
{#each users as user}
|
||||
{#each $backendUiStore.users as user}
|
||||
<li>
|
||||
<i class="ri-user-4-line" />
|
||||
<button class:active={user.id === $store.currentUserId}>
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<div>
|
||||
<h4 style="margin-bottom: 20px">Choose an Application</h4>
|
||||
{#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}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
let promise = 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()
|
||||
|
||||
if (res.ok) {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<script>
|
||||
import { store } from "builderStore";
|
||||
import AppList from "components/start/AppList.svelte"
|
||||
import { onMount } from "svelte"
|
||||
import IconButton from "components/common/IconButton.svelte"
|
||||
|
@ -7,7 +8,7 @@
|
|||
let promise = getApps()
|
||||
|
||||
async function getApps() {
|
||||
const res = await fetch(`/api/budibase/applications`)
|
||||
const res = await fetch(`/api/${$store.clientId}/applications`)
|
||||
const json = await res.json()
|
||||
|
||||
if (res.ok) {
|
||||
|
|
|
@ -1,43 +1,6 @@
|
|||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
||||
# Runtime data
|
||||
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
|
||||
node_modules/
|
||||
myapps/
|
||||
config.js
|
||||
/builder/*
|
||||
!/builder/assets/
|
||||
public/
|
||||
|
|
|
@ -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.
|
|
@ -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.
|
|
@ -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
|
||||
};
|
||||
}
|
|
@ -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.
|
@ -0,0 +1 @@
|
|||
MANIFEST-000004
|
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
2020/04/23-10:07:12.630205 70000d6bd000 Delete type=3 #1
|
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
MANIFEST-000002
|
|
@ -0,0 +1 @@
|
|||
2020/04/23-10:07:12.642112 70000dec0000 Delete type=3 #1
|
Binary file not shown.
|
@ -1,6 +1,11 @@
|
|||
const nano = require("nano")
|
||||
// const nano = require("nano")
|
||||
const PouchDB = require("pouchdb");
|
||||
|
||||
const COUCH_DB_URL =
|
||||
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;
|
||||
|
|
|
@ -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();
|
||||
};
|
|
@ -1,11 +1,11 @@
|
|||
const couchdb = require("../../db");
|
||||
const CouchDB = require("../../db");
|
||||
const {
|
||||
getPackageForBuilder,
|
||||
} = require("../../utilities/builder")
|
||||
|
||||
exports.fetch = async function(ctx) {
|
||||
const clientDb = couchdb.db.use(`client-${ctx.params.clientId}`);
|
||||
const body = await clientDb.view("client", "by_type", {
|
||||
const clientDb = new CouchDB(`client-${ctx.params.clientId}`);
|
||||
const body = await clientDb.query("client/by_type", {
|
||||
include_docs: true,
|
||||
key: ["app"]
|
||||
});
|
||||
|
@ -14,14 +14,14 @@ exports.fetch = 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);
|
||||
ctx.body = await getPackageForBuilder(ctx.config, application);
|
||||
}
|
||||
|
||||
exports.create = async function(ctx) {
|
||||
const clientDb = couchdb.db.use(`client-${ctx.params.clientId}`);
|
||||
const { id, rev } = await clientDb.insert({
|
||||
const clientDb = new CouchDB(`client-${ctx.params.clientId}`);
|
||||
const { id, rev } = await clientDb.post({
|
||||
type: "app",
|
||||
instances: [],
|
||||
...ctx.request.body,
|
||||
|
|
|
@ -1,30 +1,41 @@
|
|||
const couchdb = require("../../db");
|
||||
const jwt = require("jsonwebtoken");
|
||||
const CouchDB = require("../../db");
|
||||
const bcrypt = require("../../utilities/bcrypt");
|
||||
|
||||
const controller = {
|
||||
forgotPassword: async ctx => {
|
||||
exports.forgotPassword = async ctx => {
|
||||
};
|
||||
|
||||
},
|
||||
setPassword: async ctx => {
|
||||
exports.setPassword = async ctx => { };
|
||||
|
||||
},
|
||||
changePassword: async ctx => {
|
||||
exports.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) {
|
||||
// ctx.throw(StatusCodes.UNAUTHORIZED, "invalid username or password")
|
||||
// }
|
||||
exports.authenticate = async ctx => {
|
||||
const { username, password } = ctx.request.body;
|
||||
|
||||
// ctx.body = user.user_json
|
||||
// ctx.response.status = StatusCodes.OK
|
||||
if (!username) ctx.throw(400, "Username Required.");
|
||||
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;
|
||||
}
|
|
@ -1,10 +1,11 @@
|
|||
const couchdb = require("../../db");
|
||||
const CouchDB = require("../../db");
|
||||
|
||||
exports.create = async function(ctx) {
|
||||
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: {
|
||||
by_type: {
|
||||
map: function(doc) {
|
||||
|
@ -12,7 +13,7 @@ exports.create = async function(ctx) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}, '_design/client');
|
||||
});
|
||||
|
||||
ctx.body = {
|
||||
message: `Client Database ${clientId} successfully provisioned.`
|
||||
|
@ -22,7 +23,7 @@ exports.create = async function(ctx) {
|
|||
exports.destroy = async function(ctx) {
|
||||
const dbId = `client-${ctx.params.clientId}`;
|
||||
|
||||
await couchdb.db.destroy(dbId);
|
||||
await new CouchDB(dbId).destroy();
|
||||
|
||||
ctx.body = {
|
||||
status: 200,
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
const couchdb = require("../../db");
|
||||
const CouchDB = require("../../db");
|
||||
|
||||
exports.create = async function(ctx) {
|
||||
const instanceName = ctx.request.body.name;
|
||||
await couchdb.db.create(instanceName);
|
||||
// await couchdb.db.create(instanceName);
|
||||
|
||||
const { clientId, applicationId } = ctx.params;
|
||||
await couchdb.db.use(instanceName).insert({
|
||||
const db = new CouchDB(instanceName);
|
||||
await db.put({
|
||||
_id: "_design/database",
|
||||
metadata: {
|
||||
clientId,
|
||||
applicationId
|
||||
|
@ -17,35 +19,34 @@ exports.create = async function(ctx) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}, '_design/database');
|
||||
});
|
||||
|
||||
// Add the new instance under the app clientDB
|
||||
const clientDatabaseId = `client-${clientId}`
|
||||
const clientDb = await couchdb.db.use(clientDatabaseId);
|
||||
const clientDb = new CouchDB(clientDatabaseId);
|
||||
const budibaseApp = await clientDb.get(applicationId);
|
||||
budibaseApp.instances.push({
|
||||
id: instanceName,
|
||||
name: instanceName
|
||||
});
|
||||
await clientDb.insert(budibaseApp, budibaseApp._id);
|
||||
const instance = { id: instanceName, name: instanceName };
|
||||
budibaseApp.instances.push(instance);
|
||||
await clientDb.put(budibaseApp);
|
||||
|
||||
ctx.body = {
|
||||
message: `Instance Database ${instanceName} successfully provisioned.`,
|
||||
status: 200
|
||||
status: 200,
|
||||
instance
|
||||
}
|
||||
};
|
||||
|
||||
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");
|
||||
await couchdb.db.destroy(ctx.params.instanceId)
|
||||
await db.destroy();
|
||||
|
||||
// remove instance from client application document
|
||||
const { metadata } = designDoc;
|
||||
const clientDb = await couchdb.db.use(metadata.clientId);
|
||||
const clientDb = new CouchDB(metadata.clientId);
|
||||
const budibaseApp = await clientDb.get(metadata.applicationId);
|
||||
budibaseApp.instances = budibaseApp.instances.filter(instance => instance !== ctx.params.instanceId);
|
||||
await clientDb.insert(budibaseApp, budibaseApp._id);
|
||||
await clientDb.put(budibaseApp);
|
||||
|
||||
ctx.body = {
|
||||
message: `Instance Database ${ctx.params.instanceId} successfully destroyed.`,
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
const couchdb = require("../../db");
|
||||
const CouchDB = require("../../db");
|
||||
|
||||
exports.fetch = async function(ctx) {
|
||||
const db = couchdb.db.use(ctx.params.instanceId);
|
||||
const body = await db.view("database", "by_type", {
|
||||
const db = new CouchDB(ctx.params.instanceId);
|
||||
const body = await db.query("database/by_type", {
|
||||
include_docs: true,
|
||||
key: ["model"]
|
||||
});
|
||||
|
@ -10,8 +10,8 @@ exports.fetch = async function(ctx) {
|
|||
}
|
||||
|
||||
exports.create = async function(ctx) {
|
||||
const db = couchdb.db.use(ctx.params.instanceId);
|
||||
const newModel = await db.insert({
|
||||
const db = new CouchDB(ctx.params.instanceId);
|
||||
const newModel = await db.post({
|
||||
type: "model",
|
||||
...ctx.request.body
|
||||
});
|
||||
|
@ -27,7 +27,7 @@ exports.create = async function(ctx) {
|
|||
}`
|
||||
}
|
||||
};
|
||||
await db.insert(designDoc, designDoc._id);
|
||||
await db.put(designDoc);
|
||||
|
||||
ctx.body = {
|
||||
message: `Model ${ctx.request.body.name} created successfully.`,
|
||||
|
@ -44,21 +44,21 @@ exports.update = 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}`
|
||||
|
||||
// Delete all records for that model
|
||||
const records = await db.view("database", modelViewId);
|
||||
await db.bulk({
|
||||
docs: records.rows.map(record => ({ id: record.id, _deleted: true }))
|
||||
});
|
||||
const records = await db.query(`database/${modelViewId}`);
|
||||
await db.bulkDocs(
|
||||
records.rows.map(record => ({ id: record.id, _deleted: true }))
|
||||
);
|
||||
|
||||
// delete the "all" view
|
||||
const designDoc = await db.get("_design/database");
|
||||
delete designDoc.views[modelViewId];
|
||||
await db.insert(designDoc, designDoc._id);
|
||||
await db.put(designDoc);
|
||||
|
||||
ctx.body = {
|
||||
message: `Model ${model.id} deleted.`,
|
||||
|
|
|
@ -2,10 +2,10 @@ const couchdb = require("../../db")
|
|||
const {
|
||||
events,
|
||||
schemaValidator
|
||||
} = require("@budibase/common")
|
||||
} = require("../../../common");
|
||||
|
||||
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;
|
||||
|
||||
// validation with ajv
|
||||
|
@ -27,7 +27,7 @@ exports.save = async function(ctx) {
|
|||
const existingRecord = record._id && await db.get(record._id);
|
||||
|
||||
if (existingRecord) {
|
||||
const response = await db.insert(record, existingRecord._id)
|
||||
const response = await db.put({ ...record, _id: existingRecord._id });
|
||||
ctx.body = {
|
||||
message: "Record updated successfully.",
|
||||
status: 200,
|
||||
|
@ -36,7 +36,7 @@ exports.save = async function(ctx) {
|
|||
return;
|
||||
}
|
||||
|
||||
const response = await db.insert({
|
||||
const response = await db.post({
|
||||
modelId: ctx.params.modelId,
|
||||
type: "record",
|
||||
...record
|
||||
|
@ -54,10 +54,9 @@ exports.save = async function(ctx) {
|
|||
}
|
||||
|
||||
exports.fetch = async function(ctx) {
|
||||
const db = couchdb.db.use(ctx.params.instanceId)
|
||||
const response = await db.view(
|
||||
"database",
|
||||
ctx.params.viewName,
|
||||
const db = new CouchDB(ctx.params.instanceId)
|
||||
const response = await db.query(
|
||||
`database/${ctx.params.viewName}`,
|
||||
{
|
||||
include_docs: true
|
||||
}
|
||||
|
@ -76,6 +75,6 @@ exports.find = async function(ctx) {
|
|||
|
||||
exports.destroy = async function(ctx) {
|
||||
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);
|
||||
};
|
|
@ -1,8 +1,9 @@
|
|||
const couchdb = require("../../db");
|
||||
const CouchDB = require("../../db");
|
||||
const bcrypt = require("../../utilities/bcrypt");
|
||||
|
||||
exports.fetch = async function(ctx) {
|
||||
const database = couchdb.db.use(ctx.params.instanceId);
|
||||
const data = await database.view("database", "by_type", {
|
||||
const database = new CouchDB(ctx.params.instanceId);
|
||||
const data = await database.query("database/by_type", {
|
||||
include_docs: true,
|
||||
key: ["user"]
|
||||
});
|
||||
|
@ -11,20 +12,32 @@ exports.fetch = async function(ctx) {
|
|||
};
|
||||
|
||||
exports.create = async function(ctx) {
|
||||
const database = couchdb.db.use(ctx.params.instanceId);
|
||||
const response = await database.insert({
|
||||
...ctx.request.body,
|
||||
const database = new CouchDB(ctx.params.instanceId);
|
||||
const { username, password, name } = 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"
|
||||
});
|
||||
|
||||
ctx.body = {
|
||||
...response,
|
||||
user: {
|
||||
id: response.id,
|
||||
rev: response.rev,
|
||||
username,
|
||||
name
|
||||
},
|
||||
message: `User created successfully.`,
|
||||
status: 200
|
||||
}
|
||||
};
|
||||
|
||||
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)
|
||||
ctx.body = {
|
||||
...response,
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
const couchdb = require("../../db");
|
||||
const CouchDB = require("../../db");
|
||||
|
||||
const controller = {
|
||||
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");
|
||||
ctx.body = designDoc.views;
|
||||
},
|
||||
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 designDoc = await db.get("_design/database");
|
||||
|
@ -15,7 +15,7 @@ const controller = {
|
|||
...designDoc.views,
|
||||
[name]: viewDefinition
|
||||
};
|
||||
const newView = await db.insert(designDoc, designDoc._id);
|
||||
const newView = await db.put(designDoc);
|
||||
|
||||
ctx.body = {
|
||||
...newView,
|
||||
|
@ -24,8 +24,8 @@ const controller = {
|
|||
}
|
||||
},
|
||||
destroy: async ctx => {
|
||||
const db = couchdb.db.use(ctx.params.instanceId);
|
||||
ctx.body = await database.destroy(ctx.params.userId)
|
||||
const db = new CouchDB(ctx.params.instanceId);
|
||||
ctx.body = await db.destroy(ctx.params.userId)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,13 +14,13 @@ router.get("/_builder/api/apps", async ctx => {
|
|||
ctx.response.status = StatusCodes.OK
|
||||
})
|
||||
|
||||
router.get("/_builder/api/:appname/appPackage", async ctx => {
|
||||
const application = await ctx.master.getApplicationWithInstances(
|
||||
ctx.params.appname
|
||||
)
|
||||
ctx.body = await getPackageForBuilder(ctx.config, application)
|
||||
ctx.response.status = StatusCodes.OK
|
||||
})
|
||||
// router.get("/_builder/api/:appname/appPackage", async ctx => {
|
||||
// const application = await ctx.master.getApplicationWithInstances(
|
||||
// ctx.params.appname
|
||||
// )
|
||||
// ctx.body = await getPackageForBuilder(ctx.config, application)
|
||||
// ctx.response.status = StatusCodes.OK
|
||||
// })
|
||||
|
||||
router
|
||||
.post("/_builder/api/:appname/backend", async ctx => {
|
||||
|
|
|
@ -2,7 +2,6 @@ const supertest = require("supertest");
|
|||
const app = require("../../../../app");
|
||||
const {
|
||||
createInstanceDatabase,
|
||||
insertDocument,
|
||||
destroyDatabase
|
||||
} = require("./couchTestUtils");
|
||||
|
||||
|
|
|
@ -19,10 +19,11 @@
|
|||
"license": "AGPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"@budibase/client": "^0.0.32",
|
||||
"@budibase/common": "0.0.32",
|
||||
"@budibase/core": "^0.0.32",
|
||||
"@koa/router": "^8.0.0",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"fs-extra": "^8.1.0",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"koa": "^2.7.0",
|
||||
"koa-body": "^4.1.0",
|
||||
"koa-logger": "^3.2.1",
|
||||
|
@ -30,7 +31,7 @@
|
|||
"koa-session": "^5.12.0",
|
||||
"koa-static": "^5.0.0",
|
||||
"lodash": "^4.17.13",
|
||||
"nano": "^8.2.2",
|
||||
"pouchdb": "^7.2.1",
|
||||
"squirrelly": "^7.5.0",
|
||||
"tar-fs": "^2.0.0",
|
||||
"uuid": "^3.3.2",
|
||||
|
|
|
@ -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);
|
|
@ -28,7 +28,7 @@ const getAppDefinition = async appPath =>
|
|||
await readJSON(`${appPath}/appDefinition.json`)
|
||||
|
||||
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)
|
||||
|
||||
|
|
|
@ -336,6 +336,7 @@ module.exports = async context => {
|
|||
|
||||
const getApplicationWithInstances = async appname => {
|
||||
const app = cloneDeep(await getApplication(appname))
|
||||
|
||||
app.instances = await bb.indexApi.listItems(
|
||||
`/applications/${app.id}/allinstances`
|
||||
)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue