Global user management now functioning as expected, there were some errant db.destroy functions from the system previously, this is now cleaned up.

This commit is contained in:
mike12345567 2021-04-09 16:55:56 +01:00
parent 164ef9a22e
commit dc62087dad
4 changed files with 59 additions and 36 deletions

View File

@ -9,7 +9,7 @@ const {
InternalTables, InternalTables,
generateUserMetadataID, 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
// TODO remove special user case in future
if (tableId === InternalTables.USER_METADATA) { if (tableId === InternalTables.USER_METADATA) {
let ctx = { ctx.params = {
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 === InternalTables.USER_METADATA) { 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,6 +138,7 @@ exports.save = async function(ctx) {
} }
if (!inputs._rev && !inputs._id) { if (!inputs._rev && !inputs._id) {
// TODO remove special user case in future
if (inputs.tableId === InternalTables.USER_METADATA) { if (inputs.tableId === InternalTables.USER_METADATA) {
inputs._id = generateUserMetadataID(inputs.email) inputs._id = generateUserMetadataID(inputs.email)
} else { } else {
@ -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 === InternalTables.USER_METADATA) { 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 === InternalTables.USER_METADATA) {
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 === InternalTables.USER_METADATA) { 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,8 +337,15 @@ exports.destroy = async function(ctx) {
row, row,
tableId: row.tableId, tableId: row.tableId,
}) })
ctx.body = await db.remove(ctx.params.rowId, ctx.params.revId) // TODO remove special user case in future
ctx.status = 200 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)
}
// for automations include the row that was deleted // for automations include the row that was deleted
ctx.row = row ctx.row = row
@ -395,7 +391,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 +433,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 +441,20 @@ async function bulkDelete(ctx) {
tableId: row.tableId, tableId: row.tableId,
}) })
) )
// TODO remove special user case in future
await db.bulkDocs(rows.map(row => ({ ...row, _deleted: true }))) if (ctx.params.tableId === InternalTables.USER_METADATA) {
await Promise.all(linkUpdates) 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 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)

View File

@ -28,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
@ -75,9 +77,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 =
ctx.params.email || getEmailFromUserMetadataID(ctx.params.userId)
await deleteGlobalUser(ctx, email) await deleteGlobalUser(ctx, email)
await db.destroy(generateUserMetadataID(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.`,
} }
@ -92,5 +100,7 @@ exports.findMetadata = async function(ctx) {
ctx.body = { ctx.body = {
...global, ...global,
...user, ...user,
// make sure the ID is always a local ID, not a global one
_id: generateUserMetadataID(email),
} }
} }

View File

@ -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.`,
} }

View File

@ -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] = {