merge
This commit is contained in:
commit
e2ce7098c5
|
@ -29,7 +29,7 @@
|
||||||
"clean": "lerna clean",
|
"clean": "lerna clean",
|
||||||
"kill-port": "kill-port 4001",
|
"kill-port": "kill-port 4001",
|
||||||
"dev": "yarn run kill-port && lerna link && lerna run --parallel dev:builder --concurrency 1",
|
"dev": "yarn run kill-port && lerna link && lerna run --parallel dev:builder --concurrency 1",
|
||||||
"dev:noserver": "lerna link && lerna run --parallel dev:builder --concurrency 1 --ignore @budibase/server",
|
"dev:noserver": "lerna link && lerna run dev:stack:up && lerna run --parallel dev:builder --concurrency 1 --ignore @budibase/server --ignore @budibase/worker",
|
||||||
"test": "lerna run test",
|
"test": "lerna run test",
|
||||||
"lint": "eslint packages",
|
"lint": "eslint packages",
|
||||||
"lint:fix": "eslint --fix packages",
|
"lint:fix": "eslint --fix packages",
|
||||||
|
|
|
@ -26,13 +26,12 @@ exports.generateUserID = email => {
|
||||||
* Gets parameters for retrieving users, this is a utility function for the getDocParams function.
|
* Gets parameters for retrieving users, this is a utility function for the getDocParams function.
|
||||||
*/
|
*/
|
||||||
exports.getUserParams = (email = "", otherProps = {}) => {
|
exports.getUserParams = (email = "", otherProps = {}) => {
|
||||||
|
if (!email) {
|
||||||
|
email = ""
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
...otherProps,
|
...otherProps,
|
||||||
startkey: `${DocumentTypes.USER}${SEPARATOR}${email}`,
|
startkey: `${DocumentTypes.USER}${SEPARATOR}${email}`,
|
||||||
endkey: `${DocumentTypes.USER}${SEPARATOR}${email}${UNICODE_MAX}`,
|
endkey: `${DocumentTypes.USER}${SEPARATOR}${email}${UNICODE_MAX}`,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.getEmailFromUserID = id => {
|
|
||||||
return id.split(`${DocumentTypes.USER}${SEPARATOR}`)[1]
|
|
||||||
}
|
|
|
@ -1,7 +1,7 @@
|
||||||
import api from "builderStore/api"
|
import api from "builderStore/api"
|
||||||
|
|
||||||
export async function createUser(user) {
|
export async function createUser(user) {
|
||||||
const CREATE_USER_URL = `/api/users`
|
const CREATE_USER_URL = `/api/users/metadata`
|
||||||
const response = await api.post(CREATE_USER_URL, user)
|
const response = await api.post(CREATE_USER_URL, user)
|
||||||
return await response.json()
|
return await response.json()
|
||||||
}
|
}
|
||||||
|
@ -15,8 +15,7 @@ export async function saveRow(row, tableId) {
|
||||||
|
|
||||||
export async function deleteRow(row) {
|
export async function deleteRow(row) {
|
||||||
const DELETE_ROWS_URL = `/api/${row.tableId}/rows/${row._id}/${row._rev}`
|
const DELETE_ROWS_URL = `/api/${row.tableId}/rows/${row._id}/${row._rev}`
|
||||||
const response = await api.delete(DELETE_ROWS_URL)
|
return api.delete(DELETE_ROWS_URL)
|
||||||
return response
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchDataForView(view) {
|
export async function fetchDataForView(view) {
|
||||||
|
|
|
@ -157,7 +157,7 @@
|
||||||
password: $createAppStore.values.password,
|
password: $createAppStore.values.password,
|
||||||
roleId: $createAppStore.values.roleId,
|
roleId: $createAppStore.values.roleId,
|
||||||
}
|
}
|
||||||
const userResp = await api.post(`/api/users`, user)
|
const userResp = await api.post(`/api/users/metadata`, user)
|
||||||
const json = await userResp.json()
|
const json = await userResp.json()
|
||||||
$goto(`./${appJson._id}`)
|
$goto(`./${appJson._id}`)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
@ -41,6 +41,12 @@ module.exports = async (url, opts) => {
|
||||||
],
|
],
|
||||||
bookmark: "test",
|
bookmark: "test",
|
||||||
})
|
})
|
||||||
|
} else if (url.includes("/api/admin")) {
|
||||||
|
return json({
|
||||||
|
email: "test@test.com",
|
||||||
|
_id: "us_test@test.com",
|
||||||
|
status: "active",
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return fetch(url, opts)
|
return fetch(url, opts)
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ async function getAppUrlIfNotInUse(ctx) {
|
||||||
if (!env.SELF_HOSTED) {
|
if (!env.SELF_HOSTED) {
|
||||||
return url
|
return url
|
||||||
}
|
}
|
||||||
const deployedApps = await getDeployedApps()
|
const deployedApps = await getDeployedApps(ctx)
|
||||||
if (
|
if (
|
||||||
deployedApps[url] != null &&
|
deployedApps[url] != null &&
|
||||||
deployedApps[url].appId !== ctx.params.appId
|
deployedApps[url].appId !== ctx.params.appId
|
||||||
|
|
|
@ -3,10 +3,10 @@ const CouchDB = require("../../db")
|
||||||
const bcrypt = require("../../utilities/bcrypt")
|
const bcrypt = require("../../utilities/bcrypt")
|
||||||
const env = require("../../environment")
|
const env = require("../../environment")
|
||||||
const { getAPIKey } = require("../../utilities/usageQuota")
|
const { getAPIKey } = require("../../utilities/usageQuota")
|
||||||
const { generateUserID } = require("../../db/utils")
|
const { generateUserMetadataID } = require("../../db/utils")
|
||||||
const { setCookie } = require("../../utilities")
|
const { setCookie } = require("../../utilities")
|
||||||
const { outputProcessing } = require("../../utilities/rowProcessor")
|
const { outputProcessing } = require("../../utilities/rowProcessor")
|
||||||
const { ViewNames } = require("../../db/utils")
|
const { InternalTables } = require("../../db/utils")
|
||||||
const { UserStatus } = require("@budibase/auth")
|
const { UserStatus } = require("@budibase/auth")
|
||||||
const setBuilderToken = require("../../utilities/builder/setBuilderToken")
|
const setBuilderToken = require("../../utilities/builder/setBuilderToken")
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ exports.authenticate = async ctx => {
|
||||||
|
|
||||||
let dbUser
|
let dbUser
|
||||||
try {
|
try {
|
||||||
dbUser = await db.get(generateUserID(email))
|
dbUser = await db.get(generateUserMetadataID(email))
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
// do not want to throw a 404 - as this could be
|
// do not want to throw a 404 - as this could be
|
||||||
// used to determine valid emails
|
// used to determine valid emails
|
||||||
|
@ -84,7 +84,7 @@ exports.fetchSelf = async ctx => {
|
||||||
}
|
}
|
||||||
const db = new CouchDB(appId)
|
const db = new CouchDB(appId)
|
||||||
const user = await db.get(userId)
|
const user = await db.get(userId)
|
||||||
const userTable = await db.get(ViewNames.USERS)
|
const userTable = await db.get(InternalTables.USER_METADATA)
|
||||||
if (user) {
|
if (user) {
|
||||||
delete user.password
|
delete user.password
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,5 +40,5 @@ exports.fetchUrls = async ctx => {
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.getDeployedApps = async ctx => {
|
exports.getDeployedApps = async ctx => {
|
||||||
ctx.body = await getDeployedApps()
|
ctx.body = await getDeployedApps(ctx)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,8 @@ const {
|
||||||
const {
|
const {
|
||||||
generateRoleID,
|
generateRoleID,
|
||||||
getRoleParams,
|
getRoleParams,
|
||||||
getUserParams,
|
getUserMetadataParams,
|
||||||
ViewNames,
|
InternalTables,
|
||||||
} = require("../../db/utils")
|
} = require("../../db/utils")
|
||||||
|
|
||||||
const UpdateRolesOptions = {
|
const UpdateRolesOptions = {
|
||||||
|
@ -28,7 +28,7 @@ const EXTERNAL_BUILTIN_ROLE_IDS = [
|
||||||
]
|
]
|
||||||
|
|
||||||
async function updateRolesOnUserTable(db, roleId, updateOption) {
|
async function updateRolesOnUserTable(db, roleId, updateOption) {
|
||||||
const table = await db.get(ViewNames.USERS)
|
const table = await db.get(InternalTables.USER_METADATA)
|
||||||
const schema = table.schema
|
const schema = table.schema
|
||||||
const remove = updateOption === UpdateRolesOptions.REMOVED
|
const remove = updateOption === UpdateRolesOptions.REMOVED
|
||||||
let updated = false
|
let updated = false
|
||||||
|
@ -112,7 +112,7 @@ exports.destroy = async function(ctx) {
|
||||||
// first check no users actively attached to role
|
// first check no users actively attached to role
|
||||||
const users = (
|
const users = (
|
||||||
await db.allDocs(
|
await db.allDocs(
|
||||||
getUserParams(null, {
|
getUserMetadataParams(null, {
|
||||||
include_docs: true,
|
include_docs: true,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,10 +6,10 @@ const {
|
||||||
generateRowID,
|
generateRowID,
|
||||||
DocumentTypes,
|
DocumentTypes,
|
||||||
SEPARATOR,
|
SEPARATOR,
|
||||||
ViewNames,
|
InternalTables,
|
||||||
generateUserID,
|
generateUserMetadataID,
|
||||||
} = require("../../db/utils")
|
} = require("../../db/utils")
|
||||||
const usersController = require("./user")
|
const userController = require("./user")
|
||||||
const {
|
const {
|
||||||
inputProcessing,
|
inputProcessing,
|
||||||
outputProcessing,
|
outputProcessing,
|
||||||
|
@ -37,18 +37,14 @@ validateJs.extend(validateJs.validators.datetime, {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
async function findRow(db, appId, tableId, rowId) {
|
async function findRow(ctx, db, tableId, rowId) {
|
||||||
let row
|
let row
|
||||||
if (tableId === ViewNames.USERS) {
|
// TODO remove special user case in future
|
||||||
let ctx = {
|
if (tableId === InternalTables.USER_METADATA) {
|
||||||
params: {
|
ctx.params = {
|
||||||
userId: rowId,
|
userId: rowId,
|
||||||
},
|
|
||||||
user: {
|
|
||||||
appId,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
await usersController.findMetadata(ctx)
|
await userController.findMetadata(ctx)
|
||||||
row = ctx.body
|
row = ctx.body
|
||||||
} else {
|
} else {
|
||||||
row = await db.get(rowId)
|
row = await db.get(rowId)
|
||||||
|
@ -96,14 +92,14 @@ exports.patch = async function(ctx) {
|
||||||
table,
|
table,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Creation of a new user goes to the user controller
|
// TODO remove special user case in future
|
||||||
if (row.tableId === ViewNames.USERS) {
|
if (row.tableId === InternalTables.USER_METADATA) {
|
||||||
// the row has been updated, need to put it into the ctx
|
// the row has been updated, need to put it into the ctx
|
||||||
ctx.request.body = {
|
ctx.request.body = {
|
||||||
...row,
|
...row,
|
||||||
password: ctx.request.body.password,
|
password: ctx.request.body.password,
|
||||||
}
|
}
|
||||||
await usersController.updateMetadata(ctx)
|
await userController.updateMetadata(ctx)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,8 +138,9 @@ exports.save = async function(ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!inputs._rev && !inputs._id) {
|
if (!inputs._rev && !inputs._id) {
|
||||||
if (inputs.tableId === ViewNames.USERS) {
|
// TODO remove special user case in future
|
||||||
inputs._id = generateUserID(inputs.email)
|
if (inputs.tableId === InternalTables.USER_METADATA) {
|
||||||
|
inputs._id = generateUserMetadataID(inputs.email)
|
||||||
} else {
|
} else {
|
||||||
inputs._id = generateRowID(inputs.tableId)
|
inputs._id = generateRowID(inputs.tableId)
|
||||||
}
|
}
|
||||||
|
@ -175,11 +172,11 @@ exports.save = async function(ctx) {
|
||||||
table,
|
table,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Creation of a new user goes to the user controller
|
// TODO remove special user case in future
|
||||||
if (row.tableId === ViewNames.USERS) {
|
if (row.tableId === InternalTables.USER_METADATA) {
|
||||||
// the row has been updated, need to put it into the ctx
|
// the row has been updated, need to put it into the ctx
|
||||||
ctx.request.body = row
|
ctx.request.body = row
|
||||||
await usersController.createMetadata(ctx)
|
await userController.createMetadata(ctx)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,14 +284,6 @@ exports.search = async function(ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await search(searchString)
|
const response = await search(searchString)
|
||||||
|
|
||||||
// delete passwords from users
|
|
||||||
if (tableId === ViewNames.USERS) {
|
|
||||||
for (let row of response.rows) {
|
|
||||||
delete row.password
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const table = await db.get(tableId)
|
const table = await db.get(tableId)
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
rows: await outputProcessing(appId, table, response.rows),
|
rows: await outputProcessing(appId, table, response.rows),
|
||||||
|
@ -306,11 +295,11 @@ exports.fetchTableRows = async function(ctx) {
|
||||||
const appId = ctx.appId
|
const appId = ctx.appId
|
||||||
const db = new CouchDB(appId)
|
const db = new CouchDB(appId)
|
||||||
|
|
||||||
// special case for users, fetch through the user controller
|
// TODO remove special user case in future
|
||||||
let rows,
|
let rows,
|
||||||
table = await db.get(ctx.params.tableId)
|
table = await db.get(ctx.params.tableId)
|
||||||
if (ctx.params.tableId === ViewNames.USERS) {
|
if (ctx.params.tableId === InternalTables.USER_METADATA) {
|
||||||
await usersController.fetchMetadata(ctx)
|
await userController.fetchMetadata(ctx)
|
||||||
rows = ctx.body
|
rows = ctx.body
|
||||||
} else {
|
} else {
|
||||||
const response = await db.allDocs(
|
const response = await db.allDocs(
|
||||||
|
@ -328,7 +317,7 @@ exports.find = async function(ctx) {
|
||||||
const db = new CouchDB(appId)
|
const db = new CouchDB(appId)
|
||||||
try {
|
try {
|
||||||
const table = await db.get(ctx.params.tableId)
|
const table = await db.get(ctx.params.tableId)
|
||||||
const row = await findRow(db, appId, ctx.params.tableId, ctx.params.rowId)
|
const row = await findRow(ctx, db, ctx.params.tableId, ctx.params.rowId)
|
||||||
ctx.body = await outputProcessing(appId, table, row)
|
ctx.body = await outputProcessing(appId, table, row)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
ctx.throw(400, err)
|
ctx.throw(400, err)
|
||||||
|
@ -348,11 +337,19 @@ exports.destroy = async function(ctx) {
|
||||||
row,
|
row,
|
||||||
tableId: row.tableId,
|
tableId: row.tableId,
|
||||||
})
|
})
|
||||||
|
// TODO remove special user case in future
|
||||||
|
if (ctx.params.tableId === InternalTables.USER_METADATA) {
|
||||||
|
ctx.params = {
|
||||||
|
userId: ctx.params.rowId,
|
||||||
|
}
|
||||||
|
await userController.destroyMetadata(ctx)
|
||||||
|
} else {
|
||||||
ctx.body = await db.remove(ctx.params.rowId, ctx.params.revId)
|
ctx.body = await db.remove(ctx.params.rowId, ctx.params.revId)
|
||||||
ctx.status = 200
|
}
|
||||||
|
|
||||||
// for automations include the row that was deleted
|
// for automations include the row that was deleted
|
||||||
ctx.row = row
|
ctx.row = row
|
||||||
|
ctx.status = 200
|
||||||
ctx.eventEmitter && ctx.eventEmitter.emitRow(`row:delete`, appId, row)
|
ctx.eventEmitter && ctx.eventEmitter.emitRow(`row:delete`, appId, row)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,7 +392,7 @@ exports.fetchEnrichedRow = async function(ctx) {
|
||||||
// need table to work out where links go in row
|
// need table to work out where links go in row
|
||||||
let [table, row] = await Promise.all([
|
let [table, row] = await Promise.all([
|
||||||
db.get(tableId),
|
db.get(tableId),
|
||||||
findRow(db, appId, tableId, rowId),
|
findRow(ctx, db, tableId, rowId),
|
||||||
])
|
])
|
||||||
// get the link docs
|
// get the link docs
|
||||||
const linkVals = await linkRows.getLinkDocuments({
|
const linkVals = await linkRows.getLinkDocuments({
|
||||||
|
@ -437,7 +434,7 @@ async function bulkDelete(ctx) {
|
||||||
const { rows } = ctx.request.body
|
const { rows } = ctx.request.body
|
||||||
const db = new CouchDB(appId)
|
const db = new CouchDB(appId)
|
||||||
|
|
||||||
const linkUpdates = rows.map(row =>
|
let updates = rows.map(row =>
|
||||||
linkRows.updateLinks({
|
linkRows.updateLinks({
|
||||||
appId,
|
appId,
|
||||||
eventType: linkRows.EventType.ROW_DELETE,
|
eventType: linkRows.EventType.ROW_DELETE,
|
||||||
|
@ -445,9 +442,20 @@ async function bulkDelete(ctx) {
|
||||||
tableId: row.tableId,
|
tableId: row.tableId,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
// TODO remove special user case in future
|
||||||
|
if (ctx.params.tableId === InternalTables.USER_METADATA) {
|
||||||
|
updates = updates.concat(
|
||||||
|
rows.map(row => {
|
||||||
|
ctx.params = {
|
||||||
|
userId: row._id,
|
||||||
|
}
|
||||||
|
return userController.destroyMetadata(ctx)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
} else {
|
||||||
await db.bulkDocs(rows.map(row => ({ ...row, _deleted: true })))
|
await db.bulkDocs(rows.map(row => ({ ...row, _deleted: true })))
|
||||||
await Promise.all(linkUpdates)
|
}
|
||||||
|
await Promise.all(updates)
|
||||||
|
|
||||||
rows.forEach(row => {
|
rows.forEach(row => {
|
||||||
ctx.eventEmitter && ctx.eventEmitter.emitRow(`row:delete`, appId, row)
|
ctx.eventEmitter && ctx.eventEmitter.emitRow(`row:delete`, appId, row)
|
||||||
|
|
|
@ -22,7 +22,7 @@ const { objectStoreUrl, clientLibraryPath } = require("../../../utilities")
|
||||||
async function checkForSelfHostedURL(ctx) {
|
async function checkForSelfHostedURL(ctx) {
|
||||||
// the "appId" component of the URL may actually be a specific self hosted URL
|
// the "appId" component of the URL may actually be a specific self hosted URL
|
||||||
let possibleAppUrl = `/${encodeURI(ctx.params.appId).toLowerCase()}`
|
let possibleAppUrl = `/${encodeURI(ctx.params.appId).toLowerCase()}`
|
||||||
const apps = await getDeployedApps()
|
const apps = await getDeployedApps(ctx)
|
||||||
if (apps[possibleAppUrl] && apps[possibleAppUrl].appId) {
|
if (apps[possibleAppUrl] && apps[possibleAppUrl].appId) {
|
||||||
return apps[possibleAppUrl].appId
|
return apps[possibleAppUrl].appId
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
const CouchDB = require("../../../db")
|
const CouchDB = require("../../../db")
|
||||||
const csvParser = require("../../../utilities/csvParser")
|
const csvParser = require("../../../utilities/csvParser")
|
||||||
const { getRowParams, generateRowID, ViewNames } = require("../../../db/utils")
|
const {
|
||||||
|
getRowParams,
|
||||||
|
generateRowID,
|
||||||
|
InternalTables,
|
||||||
|
} = require("../../../db/utils")
|
||||||
const { isEqual } = require("lodash/fp")
|
const { isEqual } = require("lodash/fp")
|
||||||
const { AutoFieldSubTypes } = require("../../../constants")
|
const { AutoFieldSubTypes } = require("../../../constants")
|
||||||
const { inputProcessing } = require("../../../utilities/rowProcessor")
|
const { inputProcessing } = require("../../../utilities/rowProcessor")
|
||||||
|
@ -136,7 +140,7 @@ exports.handleSearchIndexes = async (appId, table) => {
|
||||||
|
|
||||||
exports.checkStaticTables = table => {
|
exports.checkStaticTables = table => {
|
||||||
// check user schema has all required elements
|
// check user schema has all required elements
|
||||||
if (table._id === ViewNames.USERS) {
|
if (table._id === InternalTables.USER_METADATA) {
|
||||||
for (let [key, schema] of Object.entries(USERS_TABLE_SCHEMA.schema)) {
|
for (let [key, schema] of Object.entries(USERS_TABLE_SCHEMA.schema)) {
|
||||||
// check if the schema exists on the table to be created/updated
|
// check if the schema exists on the table to be created/updated
|
||||||
if (table.schema[key] == null) {
|
if (table.schema[key] == null) {
|
||||||
|
|
|
@ -1,71 +1,23 @@
|
||||||
const CouchDB = require("../../db")
|
const CouchDB = require("../../db")
|
||||||
const {
|
const {
|
||||||
generateUserID,
|
generateUserMetadataID,
|
||||||
getUserParams,
|
getUserMetadataParams,
|
||||||
getEmailFromUserID,
|
getEmailFromUserMetadataID,
|
||||||
} = require("@budibase/auth")
|
} = require("../../db/utils")
|
||||||
const { InternalTables } = require("../../db/utils")
|
const { InternalTables } = require("../../db/utils")
|
||||||
const { getRole } = require("../../utilities/security/roles")
|
const { getRole } = require("../../utilities/security/roles")
|
||||||
const { checkSlashesInUrl } = require("../../utilities")
|
const {
|
||||||
const env = require("../../environment")
|
getGlobalUsers,
|
||||||
const fetch = require("node-fetch")
|
saveGlobalUser,
|
||||||
|
deleteGlobalUser,
|
||||||
async function deleteGlobalUser(email) {
|
} = require("../../utilities/workerRequests")
|
||||||
const endpoint = `/api/admin/users/${email}`
|
|
||||||
const reqCfg = { method: "DELETE" }
|
|
||||||
const response = await fetch(
|
|
||||||
checkSlashesInUrl(env.WORKER_URL + endpoint),
|
|
||||||
reqCfg
|
|
||||||
)
|
|
||||||
return response.json()
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getGlobalUsers(email = null) {
|
|
||||||
const endpoint = email ? `/api/admin/users/${email}` : `/api/admin/users`
|
|
||||||
const reqCfg = { method: "GET" }
|
|
||||||
const response = await fetch(
|
|
||||||
checkSlashesInUrl(env.WORKER_URL + endpoint),
|
|
||||||
reqCfg
|
|
||||||
)
|
|
||||||
return response.json()
|
|
||||||
}
|
|
||||||
|
|
||||||
async function saveGlobalUser(appId, email, body) {
|
|
||||||
const globalUser = await getGlobalUsers(email)
|
|
||||||
const roles = globalUser.roles || {}
|
|
||||||
if (body.roleId) {
|
|
||||||
roles.appId = body.roleId
|
|
||||||
}
|
|
||||||
const endpoint = `/api/admin/users`
|
|
||||||
const reqCfg = {
|
|
||||||
method: "POST",
|
|
||||||
body: {
|
|
||||||
...globalUser,
|
|
||||||
email,
|
|
||||||
password: body.password,
|
|
||||||
status: body.status,
|
|
||||||
roles,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await fetch(
|
|
||||||
checkSlashesInUrl(env.WORKER_URL + endpoint),
|
|
||||||
reqCfg
|
|
||||||
)
|
|
||||||
await response.json()
|
|
||||||
delete body.email
|
|
||||||
delete body.password
|
|
||||||
delete body.roleId
|
|
||||||
delete body.status
|
|
||||||
return body
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.fetchMetadata = async function(ctx) {
|
exports.fetchMetadata = async function(ctx) {
|
||||||
const database = new CouchDB(ctx.appId)
|
const database = new CouchDB(ctx.appId)
|
||||||
const global = await getGlobalUsers()
|
const global = await getGlobalUsers(ctx, ctx.appId)
|
||||||
const metadata = (
|
const metadata = (
|
||||||
await database.allDocs(
|
await database.allDocs(
|
||||||
getUserParams(null, {
|
getUserMetadataParams(null, {
|
||||||
include_docs: true,
|
include_docs: true,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
@ -76,6 +28,8 @@ exports.fetchMetadata = async function(ctx) {
|
||||||
users.push({
|
users.push({
|
||||||
...user,
|
...user,
|
||||||
...info,
|
...info,
|
||||||
|
// make sure the ID is always a local ID, not a global one
|
||||||
|
_id: generateUserMetadataID(user.email),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ctx.body = users
|
ctx.body = users
|
||||||
|
@ -90,17 +44,20 @@ exports.createMetadata = async function(ctx) {
|
||||||
const role = await getRole(appId, roleId)
|
const role = await getRole(appId, roleId)
|
||||||
if (!role) ctx.throw(400, "Invalid Role")
|
if (!role) ctx.throw(400, "Invalid Role")
|
||||||
|
|
||||||
const metadata = await saveGlobalUser(appId, email, ctx.request.body)
|
const metadata = await saveGlobalUser(ctx, appId, email, ctx.request.body)
|
||||||
|
|
||||||
const user = {
|
const user = {
|
||||||
...metadata,
|
...metadata,
|
||||||
_id: generateUserID(email),
|
_id: generateUserMetadataID(email),
|
||||||
type: "user",
|
type: "user",
|
||||||
tableId: InternalTables.USER_METADATA,
|
tableId: InternalTables.USER_METADATA,
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await db.post(user)
|
const response = await db.post(user)
|
||||||
|
// for automations to make it obvious was successful
|
||||||
|
ctx.status = 200
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
|
_id: response.id,
|
||||||
_rev: response.rev,
|
_rev: response.rev,
|
||||||
email,
|
email,
|
||||||
}
|
}
|
||||||
|
@ -110,11 +67,11 @@ exports.updateMetadata = async function(ctx) {
|
||||||
const appId = ctx.appId
|
const appId = ctx.appId
|
||||||
const db = new CouchDB(appId)
|
const db = new CouchDB(appId)
|
||||||
const user = ctx.request.body
|
const user = ctx.request.body
|
||||||
let email = user.email || getEmailFromUserID(user._id)
|
let email = user.email || getEmailFromUserMetadataID(user._id)
|
||||||
const metadata = await saveGlobalUser(appId, email, ctx.request.body)
|
const metadata = await saveGlobalUser(ctx, appId, email, ctx.request.body)
|
||||||
|
|
||||||
if (!metadata._id) {
|
if (!metadata._id) {
|
||||||
user._id = generateUserID(email)
|
user._id = generateUserMetadataID(email)
|
||||||
}
|
}
|
||||||
ctx.body = await db.put({
|
ctx.body = await db.put({
|
||||||
...metadata,
|
...metadata,
|
||||||
|
@ -123,9 +80,15 @@ exports.updateMetadata = async function(ctx) {
|
||||||
|
|
||||||
exports.destroyMetadata = async function(ctx) {
|
exports.destroyMetadata = async function(ctx) {
|
||||||
const db = new CouchDB(ctx.appId)
|
const db = new CouchDB(ctx.appId)
|
||||||
const email = ctx.params.email
|
const email =
|
||||||
await deleteGlobalUser(email)
|
ctx.params.email || getEmailFromUserMetadataID(ctx.params.userId)
|
||||||
await db.destroy(generateUserID(email))
|
await deleteGlobalUser(ctx, email)
|
||||||
|
try {
|
||||||
|
const dbUser = await db.get(generateUserMetadataID(email))
|
||||||
|
await db.remove(dbUser._id, dbUser._rev)
|
||||||
|
} catch (err) {
|
||||||
|
// error just means the global user has no config in this app
|
||||||
|
}
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
message: `User ${ctx.params.email} deleted.`,
|
message: `User ${ctx.params.email} deleted.`,
|
||||||
}
|
}
|
||||||
|
@ -133,12 +96,14 @@ exports.destroyMetadata = async function(ctx) {
|
||||||
|
|
||||||
exports.findMetadata = async function(ctx) {
|
exports.findMetadata = async function(ctx) {
|
||||||
const database = new CouchDB(ctx.appId)
|
const database = new CouchDB(ctx.appId)
|
||||||
let lookup = ctx.params.email
|
const email =
|
||||||
? generateUserID(ctx.params.email)
|
ctx.params.email || getEmailFromUserMetadataID(ctx.params.userId)
|
||||||
: ctx.params.userId
|
const global = await getGlobalUsers(ctx, ctx.appId, email)
|
||||||
const user = await database.get(lookup)
|
const user = await database.get(generateUserMetadataID(email))
|
||||||
if (user) {
|
ctx.body = {
|
||||||
delete user.password
|
...global,
|
||||||
|
...user,
|
||||||
|
// make sure the ID is always a local ID, not a global one
|
||||||
|
_id: generateUserMetadataID(email),
|
||||||
}
|
}
|
||||||
ctx.body = user
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ module.exports.run = async function({ inputs, appId, apiKey, emitter }) {
|
||||||
request: {
|
request: {
|
||||||
body: inputs.row,
|
body: inputs.row,
|
||||||
},
|
},
|
||||||
user: { appId },
|
appId,
|
||||||
eventEmitter: emitter,
|
eventEmitter: emitter,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,9 +62,7 @@ module.exports.definition = {
|
||||||
module.exports.run = async function({ inputs, appId, apiKey, emitter }) {
|
module.exports.run = async function({ inputs, appId, apiKey, emitter }) {
|
||||||
const { email, password, roleId } = inputs
|
const { email, password, roleId } = inputs
|
||||||
const ctx = {
|
const ctx = {
|
||||||
user: {
|
appId,
|
||||||
appId: appId,
|
|
||||||
},
|
|
||||||
request: {
|
request: {
|
||||||
body: { email, password, roleId },
|
body: { email, password, roleId },
|
||||||
},
|
},
|
||||||
|
@ -79,7 +77,7 @@ module.exports.run = async function({ inputs, appId, apiKey, emitter }) {
|
||||||
return {
|
return {
|
||||||
response: ctx.body,
|
response: ctx.body,
|
||||||
// internal property not returned through the API
|
// internal property not returned through the API
|
||||||
id: ctx.userId,
|
id: ctx.body._id,
|
||||||
revision: ctx.body._rev,
|
revision: ctx.body._rev,
|
||||||
success: ctx.status === 200,
|
success: ctx.status === 200,
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,7 @@ module.exports.run = async function({ inputs, appId, apiKey, emitter }) {
|
||||||
rowId: inputs.id,
|
rowId: inputs.id,
|
||||||
revId: inputs.revision,
|
revId: inputs.revision,
|
||||||
},
|
},
|
||||||
user: { appId },
|
appId,
|
||||||
eventEmitter: emitter,
|
eventEmitter: emitter,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,7 @@ module.exports.run = async function({ inputs, appId, emitter }) {
|
||||||
request: {
|
request: {
|
||||||
body: inputs.row,
|
body: inputs.row,
|
||||||
},
|
},
|
||||||
user: { appId },
|
appId,
|
||||||
eventEmitter: emitter,
|
eventEmitter: emitter,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
require("../../environment")
|
||||||
const automation = require("../index")
|
const automation = require("../index")
|
||||||
const usageQuota = require("../../utilities/usageQuota")
|
const usageQuota = require("../../utilities/usageQuota")
|
||||||
const thread = require("../thread")
|
const thread = require("../thread")
|
||||||
const triggers = require("../triggers")
|
const triggers = require("../triggers")
|
||||||
const { basicAutomation, basicTable } = require("../../tests/utilities/structures")
|
const { basicAutomation, basicTable } = require("../../tests/utilities/structures")
|
||||||
const { wait } = require("../../utilities")
|
const { wait } = require("../../utilities")
|
||||||
const env = require("../../environment")
|
|
||||||
const { makePartial } = require("../../tests/utilities")
|
const { makePartial } = require("../../tests/utilities")
|
||||||
const { cleanInputValues } = require("../automationUtils")
|
const { cleanInputValues } = require("../automationUtils")
|
||||||
const setup = require("./utilities")
|
const setup = require("./utilities")
|
||||||
|
|
|
@ -26,6 +26,7 @@ describe("test the create row action", () => {
|
||||||
})
|
})
|
||||||
expect(res.id).toBeDefined()
|
expect(res.id).toBeDefined()
|
||||||
expect(res.revision).toBeDefined()
|
expect(res.revision).toBeDefined()
|
||||||
|
expect(res.success).toEqual(true)
|
||||||
const gottenRow = await config.getRow(table._id, res.id)
|
const gottenRow = await config.getRow(table._id, res.id)
|
||||||
expect(gottenRow.name).toEqual("test")
|
expect(gottenRow.name).toEqual("test")
|
||||||
expect(gottenRow.description).toEqual("test")
|
expect(gottenRow.description).toEqual("test")
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
const usageQuota = require("../../utilities/usageQuota")
|
const usageQuota = require("../../utilities/usageQuota")
|
||||||
const env = require("../../environment")
|
|
||||||
const setup = require("./utilities")
|
const setup = require("./utilities")
|
||||||
const { BUILTIN_ROLE_IDS } = require("../../utilities/security/roles")
|
const { BUILTIN_ROLE_IDS } = require("../../utilities/security/roles")
|
||||||
const { ViewNames } = require("../../db/utils")
|
const { InternalTables } = require("../../db/utils")
|
||||||
|
|
||||||
jest.mock("../../utilities/usageQuota")
|
jest.mock("../../utilities/usageQuota")
|
||||||
|
|
||||||
|
@ -25,8 +24,7 @@ describe("test the create user action", () => {
|
||||||
const res = await setup.runStep(setup.actions.CREATE_USER.stepId, user)
|
const res = await setup.runStep(setup.actions.CREATE_USER.stepId, user)
|
||||||
expect(res.id).toBeDefined()
|
expect(res.id).toBeDefined()
|
||||||
expect(res.revision).toBeDefined()
|
expect(res.revision).toBeDefined()
|
||||||
const userDoc = await config.getRow(ViewNames.USERS, res.id)
|
const userDoc = await config.getRow(InternalTables.USER_METADATA, res.id)
|
||||||
expect(userDoc.email).toEqual(user.email)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should return an error if no inputs provided", async () => {
|
it("should return an error if no inputs provided", async () => {
|
||||||
|
|
|
@ -116,17 +116,19 @@ exports.getRowParams = (tableId = null, rowId = null, otherProps = {}) => {
|
||||||
/**
|
/**
|
||||||
* Gets a new row ID for the specified table.
|
* Gets a new row ID for the specified table.
|
||||||
* @param {string} tableId The table which the row is being created for.
|
* @param {string} tableId The table which the row is being created for.
|
||||||
|
* @param {string|null} id If an ID is to be used then the UUID can be substituted for this.
|
||||||
* @returns {string} The new ID which a row doc can be stored under.
|
* @returns {string} The new ID which a row doc can be stored under.
|
||||||
*/
|
*/
|
||||||
exports.generateRowID = tableId => {
|
exports.generateRowID = (tableId, id = null) => {
|
||||||
return `${DocumentTypes.ROW}${SEPARATOR}${tableId}${SEPARATOR}${newid()}`
|
id = id || newid()
|
||||||
|
return `${DocumentTypes.ROW}${SEPARATOR}${tableId}${SEPARATOR}${id}`
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets parameters for retrieving users, this is a utility function for the getDocParams function.
|
* Gets parameters for retrieving users, this is a utility function for the getDocParams function.
|
||||||
*/
|
*/
|
||||||
exports.getUserParams = (email = "", otherProps = {}) => {
|
exports.getUserMetadataParams = (email = "", otherProps = {}) => {
|
||||||
return exports.getRowParams(ViewNames.USERS, email, otherProps)
|
return exports.getRowParams(InternalTables.USER_METADATA, email, otherProps)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -134,8 +136,17 @@ exports.getUserParams = (email = "", otherProps = {}) => {
|
||||||
* @param {string} email The email which the ID is going to be built up of.
|
* @param {string} email The email which the ID is going to be built up of.
|
||||||
* @returns {string} The new user ID which the user doc can be stored under.
|
* @returns {string} The new user ID which the user doc can be stored under.
|
||||||
*/
|
*/
|
||||||
exports.generateUserID = email => {
|
exports.generateUserMetadataID = email => {
|
||||||
return `${DocumentTypes.ROW}${SEPARATOR}${ViewNames.USERS}${SEPARATOR}${DocumentTypes.USER}${SEPARATOR}${email}`
|
return exports.generateRowID(InternalTables.USER_METADATA, email)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Breaks up the ID to get the email address back out of it.
|
||||||
|
*/
|
||||||
|
exports.getEmailFromUserMetadataID = id => {
|
||||||
|
return id.split(
|
||||||
|
`${DocumentTypes.ROW}${SEPARATOR}${InternalTables.USER_METADATA}${SEPARATOR}`
|
||||||
|
)[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -20,9 +20,7 @@ class TestConfiguration {
|
||||||
this.ctx = {
|
this.ctx = {
|
||||||
throw: this.throw,
|
throw: this.throw,
|
||||||
next: this.next,
|
next: this.next,
|
||||||
user: {
|
appId: "test",
|
||||||
appId: "test"
|
|
||||||
},
|
|
||||||
request: {
|
request: {
|
||||||
body: {}
|
body: {}
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,6 +2,7 @@ const CouchDB = require("../../db")
|
||||||
const { StaticDatabases } = require("../../db/utils")
|
const { StaticDatabases } = require("../../db/utils")
|
||||||
const fetch = require("node-fetch")
|
const fetch = require("node-fetch")
|
||||||
const env = require("../../environment")
|
const env = require("../../environment")
|
||||||
|
const { getDeployedApps } = require("../../utilities/workerRequests")
|
||||||
|
|
||||||
const PROD_HOSTING_URL = "app.budi.live"
|
const PROD_HOSTING_URL = "app.budi.live"
|
||||||
|
|
||||||
|
@ -84,30 +85,4 @@ exports.getTemplatesUrl = async (appId, type, name) => {
|
||||||
return `${protocol}${hostingInfo.templatesUrl}/${path}`
|
return `${protocol}${hostingInfo.templatesUrl}/${path}`
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.getDeployedApps = async () => {
|
exports.getDeployedApps = getDeployedApps
|
||||||
if (!env.SELF_HOSTED) {
|
|
||||||
throw "Can only check apps for self hosted environments"
|
|
||||||
}
|
|
||||||
const workerUrl = env.WORKER_URL
|
|
||||||
const hostingKey = env.HOSTING_KEY
|
|
||||||
try {
|
|
||||||
const response = await fetch(`${workerUrl}/api/apps`, {
|
|
||||||
method: "GET",
|
|
||||||
headers: {
|
|
||||||
"x-budibase-auth": hostingKey,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
const json = await response.json()
|
|
||||||
const apps = {}
|
|
||||||
for (let [key, value] of Object.entries(json)) {
|
|
||||||
if (value.url) {
|
|
||||||
value.url = value.url.toLowerCase()
|
|
||||||
apps[key] = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return apps
|
|
||||||
} catch (err) {
|
|
||||||
// error, cannot determine deployed apps, don't stop app creation - sort this later
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
const fetch = require("node-fetch")
|
||||||
|
const env = require("../environment")
|
||||||
|
const { checkSlashesInUrl } = require("./index")
|
||||||
|
const { BUILTIN_ROLE_IDS } = require("./security/roles")
|
||||||
|
|
||||||
|
function getAppRole(appId, user) {
|
||||||
|
if (!user.roles) {
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
user.roleId = user.roles[appId]
|
||||||
|
if (!user.roleId) {
|
||||||
|
user.roleId = BUILTIN_ROLE_IDS.PUBLIC
|
||||||
|
}
|
||||||
|
delete user.roles
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
|
||||||
|
function prepRequest(ctx, request) {
|
||||||
|
if (!request.headers) {
|
||||||
|
request.headers = {}
|
||||||
|
}
|
||||||
|
if (request.body) {
|
||||||
|
request.headers["Content-Type"] = "application/json"
|
||||||
|
request.body =
|
||||||
|
typeof request.body === "object"
|
||||||
|
? JSON.stringify(request.body)
|
||||||
|
: request.body
|
||||||
|
}
|
||||||
|
if (ctx.headers) {
|
||||||
|
request.headers.cookie = ctx.headers.cookie
|
||||||
|
}
|
||||||
|
return request
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.getDeployedApps = async ctx => {
|
||||||
|
if (!env.SELF_HOSTED) {
|
||||||
|
throw "Can only check apps for self hosted environments"
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
checkSlashesInUrl(env.WORKER_URL + `/api/apps`),
|
||||||
|
prepRequest(ctx, {
|
||||||
|
method: "GET",
|
||||||
|
})
|
||||||
|
)
|
||||||
|
const json = await response.json()
|
||||||
|
const apps = {}
|
||||||
|
for (let [key, value] of Object.entries(json)) {
|
||||||
|
if (value.url) {
|
||||||
|
value.url = value.url.toLowerCase()
|
||||||
|
apps[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return apps
|
||||||
|
} catch (err) {
|
||||||
|
// error, cannot determine deployed apps, don't stop app creation - sort this later
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.deleteGlobalUser = async (ctx, email) => {
|
||||||
|
const endpoint = `/api/admin/users/${email}`
|
||||||
|
const reqCfg = { method: "DELETE" }
|
||||||
|
const response = await fetch(
|
||||||
|
checkSlashesInUrl(env.WORKER_URL + endpoint),
|
||||||
|
prepRequest(ctx, reqCfg)
|
||||||
|
)
|
||||||
|
return response.json()
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.getGlobalUsers = async (ctx, appId, email = null) => {
|
||||||
|
const endpoint = email ? `/api/admin/users/${email}` : `/api/admin/users`
|
||||||
|
const reqCfg = { method: "GET" }
|
||||||
|
const response = await fetch(
|
||||||
|
checkSlashesInUrl(env.WORKER_URL + endpoint),
|
||||||
|
prepRequest(ctx, reqCfg)
|
||||||
|
)
|
||||||
|
let users = await response.json()
|
||||||
|
if (Array.isArray(users)) {
|
||||||
|
users = users.map(user => getAppRole(appId, user))
|
||||||
|
} else {
|
||||||
|
users = getAppRole(appId, users)
|
||||||
|
}
|
||||||
|
return users
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.saveGlobalUser = async (ctx, appId, email, body) => {
|
||||||
|
const globalUser = await exports.getGlobalUsers(ctx, appId, email)
|
||||||
|
const roles = globalUser.roles || {}
|
||||||
|
if (body.roleId) {
|
||||||
|
roles[appId] = body.roleId
|
||||||
|
}
|
||||||
|
const endpoint = `/api/admin/users`
|
||||||
|
const reqCfg = {
|
||||||
|
method: "POST",
|
||||||
|
body: {
|
||||||
|
...globalUser,
|
||||||
|
email,
|
||||||
|
password: body.password,
|
||||||
|
status: body.status,
|
||||||
|
roles,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(
|
||||||
|
checkSlashesInUrl(env.WORKER_URL + endpoint),
|
||||||
|
prepRequest(ctx, reqCfg)
|
||||||
|
)
|
||||||
|
const json = await response.json()
|
||||||
|
if (json.status !== 200 && response.status !== 200) {
|
||||||
|
ctx.throw(400, "Unable to save global user.")
|
||||||
|
}
|
||||||
|
delete body.email
|
||||||
|
delete body.password
|
||||||
|
delete body.roleId
|
||||||
|
delete body.status
|
||||||
|
return body
|
||||||
|
}
|
|
@ -17,8 +17,8 @@ exports.userSave = async ctx => {
|
||||||
...ctx.request.body,
|
...ctx.request.body,
|
||||||
_id: generateUserID(email),
|
_id: generateUserID(email),
|
||||||
password: hashedPassword,
|
password: hashedPassword,
|
||||||
},
|
}
|
||||||
dbUser
|
let dbUser
|
||||||
// in-case user existed already
|
// in-case user existed already
|
||||||
if (_id) {
|
if (_id) {
|
||||||
dbUser = await db.get(_id)
|
dbUser = await db.get(_id)
|
||||||
|
@ -48,7 +48,8 @@ exports.userSave = async ctx => {
|
||||||
|
|
||||||
exports.userDelete = async ctx => {
|
exports.userDelete = async ctx => {
|
||||||
const db = new CouchDB(USER_DB)
|
const db = new CouchDB(USER_DB)
|
||||||
await db.destroy(generateUserID(ctx.params.email))
|
const dbUser = await db.get(generateUserID(ctx.params.email))
|
||||||
|
await db.remove(dbUser._id, dbUser._rev)
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
message: `User ${ctx.params.email} deleted.`,
|
message: `User ${ctx.params.email} deleted.`,
|
||||||
}
|
}
|
||||||
|
@ -57,13 +58,12 @@ exports.userDelete = async ctx => {
|
||||||
// called internally by app server user fetch
|
// called internally by app server user fetch
|
||||||
exports.userFetch = async ctx => {
|
exports.userFetch = async ctx => {
|
||||||
const db = new CouchDB(USER_DB)
|
const db = new CouchDB(USER_DB)
|
||||||
const users = (
|
const response = await db.allDocs(
|
||||||
await db.allDocs(
|
|
||||||
getUserParams(null, {
|
getUserParams(null, {
|
||||||
include_docs: true,
|
include_docs: true,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
).rows.map(row => row.doc)
|
const users = response.rows.map(row => row.doc)
|
||||||
// user hashed password shouldn't ever be returned
|
// user hashed password shouldn't ever be returned
|
||||||
for (let user of users) {
|
for (let user of users) {
|
||||||
if (user) {
|
if (user) {
|
||||||
|
@ -76,7 +76,13 @@ exports.userFetch = async ctx => {
|
||||||
// called internally by app server user find
|
// called internally by app server user find
|
||||||
exports.userFind = async ctx => {
|
exports.userFind = async ctx => {
|
||||||
const db = new CouchDB(USER_DB)
|
const db = new CouchDB(USER_DB)
|
||||||
const user = await db.get(generateUserID(ctx.params.email))
|
let user
|
||||||
|
try {
|
||||||
|
user = await db.get(generateUserID(ctx.params.email))
|
||||||
|
} catch (err) {
|
||||||
|
// no user found, just return nothing
|
||||||
|
user = {}
|
||||||
|
}
|
||||||
if (user) {
|
if (user) {
|
||||||
delete user.password
|
delete user.password
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,9 +15,14 @@ exports.getApps = async ctx => {
|
||||||
}
|
}
|
||||||
const appDbNames = allDbs.filter(dbName => dbName.startsWith(APP_PREFIX))
|
const appDbNames = allDbs.filter(dbName => dbName.startsWith(APP_PREFIX))
|
||||||
const appPromises = appDbNames.map(db => new CouchDB(db).get(db))
|
const appPromises = appDbNames.map(db => new CouchDB(db).get(db))
|
||||||
const apps = await Promise.all(appPromises)
|
|
||||||
|
const apps = await Promise.allSettled(appPromises)
|
||||||
const body = {}
|
const body = {}
|
||||||
for (let app of apps) {
|
for (let app of apps) {
|
||||||
|
if (app.status !== "fulfilled") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
app = app.value
|
||||||
let url = app.url || encodeURI(`${app.name}`)
|
let url = app.url || encodeURI(`${app.name}`)
|
||||||
url = `/${url.replace(URL_REGEX_SLASH, "")}`
|
url = `/${url.replace(URL_REGEX_SLASH, "")}`
|
||||||
body[url] = {
|
body[url] = {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
const Router = require("@koa/router")
|
const Router = require("@koa/router")
|
||||||
const controller = require("../controllers/app")
|
const controller = require("../controllers/app")
|
||||||
const checkKey = require("../../middleware/check-key")
|
const authenticated = require("../../middleware/authenticated")
|
||||||
|
|
||||||
const router = Router()
|
const router = Router()
|
||||||
|
|
||||||
router.get("/api/apps", checkKey, controller.getApps)
|
router.get("/api/apps", authenticated, controller.getApps)
|
||||||
|
|
||||||
module.exports = router
|
module.exports = router
|
||||||
|
|
Loading…
Reference in New Issue