Fixing issues with the user table within the apps.

This commit is contained in:
mike12345567 2021-05-19 15:55:00 +01:00
parent dbf8e426bc
commit 8c68f1c134
7 changed files with 70 additions and 57 deletions

View File

@ -190,7 +190,7 @@ exports.getAllApps = async ({ dev, all } = {}) => {
} else {
return apps.map(app => ({
...app,
status: isDevApp(app) ? "development" : "published"
status: isDevApp(app) ? "development" : "published",
}))
}
}

View File

@ -112,6 +112,9 @@ exports.isClient = ctx => {
* @return {Promise<object|null>}
*/
exports.getGlobalUserByEmail = async email => {
if (email == null) {
throw "Must supply an email address to view"
}
const db = getDB(StaticDatabases.GLOBAL.name)
try {
let users = (

View File

@ -85,10 +85,6 @@
bind:value={row.email}
readonly={!creating}
/>
<RowFieldControl
meta={{ name: "password", type: "password" }}
bind:value={row.password}
/>
<RowFieldControl
meta={{ ...tableSchema.firstName, name: "First Name" }}
bind:value={row.firstName}
@ -107,16 +103,6 @@
getOptionLabel={role => role.name}
getOptionValue={role => role._id}
/>
<Select
label="Status"
bind:value={row.status}
options={[
{ label: "Active", value: "active" },
{ label: "Inactive", value: "inactive" },
]}
getOptionLabel={status => status.label}
getOptionValue={status => status.value}
/>
{#each customSchemaKeys as [key, meta]}
{#if !meta.autocolumn}
<RowFieldControl {meta} bind:value={row[key]} {creating} />

View File

@ -56,13 +56,28 @@ async function findRow(ctx, db, tableId, rowId) {
exports.patch = async function (ctx) {
const appId = ctx.appId
const db = new CouchDB(appId)
let dbRow = await db.get(ctx.params.rowId)
let dbTable = await db.get(dbRow.tableId)
const patchfields = ctx.request.body
const inputs = ctx.request.body
const tableId = inputs.tableId
const isUserTable = tableId === InternalTables.USER_METADATA
let dbRow
try {
dbRow = await db.get(ctx.params.rowId)
} catch (err) {
if (isUserTable) {
// don't include the rev, it'll be the global rev
// this time
dbRow = {
_id: inputs._id,
}
} else {
ctx.throw(400, "Row does not exist")
}
}
let dbTable = await db.get(tableId)
// need to build up full patch fields before coerce
for (let key of Object.keys(patchfields)) {
for (let key of Object.keys(inputs)) {
if (!dbTable.schema[key]) continue
dbRow[key] = patchfields[key]
dbRow[key] = inputs[key]
}
// this returns the table and row incase they have been updated
@ -90,13 +105,9 @@ exports.patch = async function (ctx) {
table,
})
// TODO remove special user case in future
if (row.tableId === InternalTables.USER_METADATA) {
if (isUserTable) {
// the row has been updated, need to put it into the ctx
ctx.request.body = {
...row,
password: ctx.request.body.password,
}
ctx.request.body = row
await userController.updateMetadata(ctx)
return
}
@ -129,13 +140,10 @@ exports.save = async function (ctx) {
// if the row obj had an _id then it will have been retrieved
if (inputs._id && inputs._rev) {
const existingRow = await db.get(inputs._id)
if (existingRow) {
ctx.params.rowId = inputs._id
await exports.patch(ctx)
return
}
}
if (!inputs._rev && !inputs._id) {
inputs._id = generateRowID(inputs.tableId)
@ -167,13 +175,6 @@ exports.save = async function (ctx) {
table,
})
if (row.tableId === InternalTables.USER_METADATA && row._id) {
// the row has been updated, need to put it into the ctx
ctx.request.body = row
await userController.updateMetadata(ctx)
return
}
row.type = "row"
const response = await db.put(row)
// don't worry about rev, tables handle rev/lastID updates

View File

@ -5,7 +5,10 @@ const {
} = require("../../db/utils")
const { InternalTables } = require("../../db/utils")
const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles")
const { getGlobalUsers, addAppRoleToSelf } = require("../../utilities/workerRequests")
const {
getGlobalUsers,
addAppRoleToUser,
} = require("../../utilities/workerRequests")
const { getFullUser } = require("../../utilities/users")
function removeGlobalProps(user) {
@ -46,7 +49,7 @@ exports.updateSelfMetadata = async function (ctx) {
ctx.request.body._id = ctx.user._id
if (ctx.user.builder && ctx.user.builder.global) {
// specific case, update self role in global user
await addAppRoleToSelf(ctx, ctx.appId, BUILTIN_ROLE_IDS.ADMIN)
await addAppRoleToUser(ctx, ctx.appId, BUILTIN_ROLE_IDS.ADMIN)
}
// make sure no stale rev
delete ctx.request.body._rev
@ -57,10 +60,12 @@ exports.updateMetadata = async function (ctx) {
const appId = ctx.appId
const db = new CouchDB(appId)
const user = removeGlobalProps(ctx.request.body)
if (user.roleId) {
await addAppRoleToUser(ctx, appId, user.roleId, user._id)
}
const metadata = {
tableId: InternalTables.USER_METADATA,
_id: user._id,
_rev: user._rev,
...user,
}
ctx.body = await db.put(metadata)
}

View File

@ -3,6 +3,7 @@ const env = require("../environment")
const { checkSlashesInUrl } = require("./index")
const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles")
const { getDeployedAppID } = require("@budibase/auth/db")
const { getGlobalIDFromUserMetadataID } = require("../db/utils")
function getAppRole(appId, user) {
if (!user.roles) {
@ -131,21 +132,33 @@ exports.getGlobalSelf = async ctx => {
return json
}
exports.addAppRoleToSelf = async (ctx, appId, roleId) => {
const self = await exports.getGlobalSelf(ctx)
const endpoint = `/api/admin/users/self`
const reqCfg = {
method: "POST",
body: {
roles: {
...self.roles,
[appId]: roleId,
exports.addAppRoleToUser = async (ctx, appId, roleId, userId = null) => {
appId = getDeployedAppID(appId)
let user,
endpoint,
body = {}
if (!userId) {
user = await exports.getGlobalSelf(ctx)
endpoint = `/api/admin/users/self`
} else {
userId = getGlobalIDFromUserMetadataID(userId)
user = await exports.getGlobalUsers(ctx, appId, userId)
body._id = userId
endpoint = `/api/admin/users`
}
body = {
...body,
roles: {
...user.roles,
[appId]: roleId,
},
}
const response = await fetch(
checkSlashesInUrl(env.WORKER_URL + endpoint),
request(ctx, reqCfg)
request(ctx, {
method: "POST",
body,
})
)
const json = await response.json()
if (json.status !== 200 && response.status !== 200) {

View File

@ -16,10 +16,15 @@ exports.save = async ctx => {
const { email, password, _id } = ctx.request.body
// make sure another user isn't using the same email
const dbUser = await getGlobalUserByEmail(email)
let dbUser
if (email) {
dbUser = await getGlobalUserByEmail(email)
if (dbUser != null && (dbUser._id !== _id || Array.isArray(dbUser))) {
ctx.throw(400, "Email address already in use.")
}
} else {
dbUser = await db.get(_id)
}
// get the password, make sure one is defined
let hashedPassword