Updating row controller to make sure that all user requests (bar deletion) are passed through correctly to the user controller so that any logic such as removing user password can be correctly held in the user controller logic.
This commit is contained in:
parent
4d5ac0ee9e
commit
36432a490f
|
@ -9,7 +9,7 @@ const {
|
||||||
ViewNames,
|
ViewNames,
|
||||||
} = require("../../db/utils")
|
} = require("../../db/utils")
|
||||||
const usersController = require("./user")
|
const usersController = require("./user")
|
||||||
const { cloneDeep } = require("lodash")
|
const { coerceRowValues } = require("../../utilities")
|
||||||
|
|
||||||
const TABLE_VIEW_BEGINS_WITH = `all${SEPARATOR}${DocumentTypes.TABLE}${SEPARATOR}`
|
const TABLE_VIEW_BEGINS_WITH = `all${SEPARATOR}${DocumentTypes.TABLE}${SEPARATOR}`
|
||||||
|
|
||||||
|
@ -29,11 +29,24 @@ validateJs.extend(validateJs.validators.datetime, {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
// lots of row functionality too specific to pass to user controller, simply handle the
|
async function findRow(db, appId, tableId, rowId) {
|
||||||
// password deletion here
|
let row
|
||||||
function removePassword(tableId, row) {
|
|
||||||
if (tableId === ViewNames.USERS) {
|
if (tableId === ViewNames.USERS) {
|
||||||
delete row.password
|
let ctx = {
|
||||||
|
params: {
|
||||||
|
userId: rowId,
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
appId,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
await usersController.find(ctx)
|
||||||
|
row = ctx.body
|
||||||
|
} else {
|
||||||
|
row = await db.get(rowId)
|
||||||
|
}
|
||||||
|
if (row.tableId !== tableId) {
|
||||||
|
throw "Supplied tableId does not match the rows tableId"
|
||||||
}
|
}
|
||||||
return row
|
return row
|
||||||
}
|
}
|
||||||
|
@ -224,13 +237,12 @@ exports.fetchTableRows = async function(ctx) {
|
||||||
exports.find = async function(ctx) {
|
exports.find = async function(ctx) {
|
||||||
const appId = ctx.user.appId
|
const appId = ctx.user.appId
|
||||||
const db = new CouchDB(appId)
|
const db = new CouchDB(appId)
|
||||||
let row = await db.get(ctx.params.rowId)
|
try {
|
||||||
if (row.tableId !== ctx.params.tableId) {
|
const row = await findRow(db, appId, ctx.params.tableId, ctx.params.rowId)
|
||||||
ctx.throw(400, "Supplied tableId does not match the rows tableId")
|
ctx.body = await linkRows.attachLinkInfo(appId, row)
|
||||||
return
|
} catch (err) {
|
||||||
|
ctx.throw(400, err)
|
||||||
}
|
}
|
||||||
row = removePassword(ctx.params.tableId, row)
|
|
||||||
ctx.body = await linkRows.attachLinkInfo(appId, row)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.destroy = async function(ctx) {
|
exports.destroy = async function(ctx) {
|
||||||
|
@ -296,8 +308,10 @@ exports.fetchEnrichedRow = async function(ctx) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 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([db.get(tableId), db.get(rowId)])
|
let [table, row] = await Promise.all([
|
||||||
row = removePassword(tableId, row)
|
db.get(tableId),
|
||||||
|
findRow(db, appId, tableId, rowId),
|
||||||
|
])
|
||||||
// get the link docs
|
// get the link docs
|
||||||
const linkVals = await linkRows.getLinkDocuments({
|
const linkVals = await linkRows.getLinkDocuments({
|
||||||
appId,
|
appId,
|
||||||
|
@ -327,68 +341,6 @@ exports.fetchEnrichedRow = async function(ctx) {
|
||||||
ctx.status = 200
|
ctx.status = 200
|
||||||
}
|
}
|
||||||
|
|
||||||
function coerceRowValues(record, table) {
|
|
||||||
const row = cloneDeep(record)
|
|
||||||
for (let [key, value] of Object.entries(row)) {
|
|
||||||
const field = table.schema[key]
|
|
||||||
if (!field) continue
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-prototype-builtins
|
|
||||||
if (TYPE_TRANSFORM_MAP[field.type].hasOwnProperty(value)) {
|
|
||||||
row[key] = TYPE_TRANSFORM_MAP[field.type][value]
|
|
||||||
} else if (TYPE_TRANSFORM_MAP[field.type].parse) {
|
|
||||||
row[key] = TYPE_TRANSFORM_MAP[field.type].parse(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return row
|
|
||||||
}
|
|
||||||
|
|
||||||
const TYPE_TRANSFORM_MAP = {
|
|
||||||
link: {
|
|
||||||
"": [],
|
|
||||||
[null]: [],
|
|
||||||
[undefined]: undefined,
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
"": "",
|
|
||||||
[null]: "",
|
|
||||||
[undefined]: undefined,
|
|
||||||
},
|
|
||||||
string: {
|
|
||||||
"": "",
|
|
||||||
[null]: "",
|
|
||||||
[undefined]: undefined,
|
|
||||||
},
|
|
||||||
longform: {
|
|
||||||
"": "",
|
|
||||||
[null]: "",
|
|
||||||
[undefined]: undefined,
|
|
||||||
},
|
|
||||||
number: {
|
|
||||||
"": null,
|
|
||||||
[null]: null,
|
|
||||||
[undefined]: undefined,
|
|
||||||
parse: n => parseFloat(n),
|
|
||||||
},
|
|
||||||
datetime: {
|
|
||||||
"": null,
|
|
||||||
[undefined]: undefined,
|
|
||||||
[null]: null,
|
|
||||||
},
|
|
||||||
attachment: {
|
|
||||||
"": [],
|
|
||||||
[null]: [],
|
|
||||||
[undefined]: undefined,
|
|
||||||
},
|
|
||||||
boolean: {
|
|
||||||
"": null,
|
|
||||||
[null]: null,
|
|
||||||
[undefined]: undefined,
|
|
||||||
true: true,
|
|
||||||
false: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
async function bulkDelete(ctx) {
|
async function bulkDelete(ctx) {
|
||||||
const appId = ctx.user.appId
|
const appId = ctx.user.appId
|
||||||
const { rows } = ctx.request.body
|
const { rows } = ctx.request.body
|
||||||
|
|
|
@ -89,9 +89,12 @@ exports.destroy = async function(ctx) {
|
||||||
|
|
||||||
exports.find = async function(ctx) {
|
exports.find = async function(ctx) {
|
||||||
const database = new CouchDB(ctx.user.appId)
|
const database = new CouchDB(ctx.user.appId)
|
||||||
const user = await database.get(generateUserID(ctx.params.email))
|
let lookup = ctx.params.email
|
||||||
ctx.body = {
|
? generateUserID(ctx.params.email)
|
||||||
email: user.email,
|
: ctx.params.userId
|
||||||
_rev: user._rev,
|
const user = await database.get(lookup)
|
||||||
|
if (user) {
|
||||||
|
delete user.password
|
||||||
}
|
}
|
||||||
|
ctx.body = user
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,8 +51,6 @@ describe("/rows", () => {
|
||||||
|
|
||||||
|
|
||||||
describe("save, load, update, delete", () => {
|
describe("save, load, update, delete", () => {
|
||||||
|
|
||||||
|
|
||||||
it("returns a success message when the row is created", async () => {
|
it("returns a success message when the row is created", async () => {
|
||||||
const res = await createRow()
|
const res = await createRow()
|
||||||
expect(res.res.statusMessage).toEqual(`${table.name} saved successfully`)
|
expect(res.res.statusMessage).toEqual(`${table.name} saved successfully`)
|
||||||
|
|
|
@ -1,8 +1,59 @@
|
||||||
const env = require("../environment")
|
const env = require("../environment")
|
||||||
const { DocumentTypes, SEPARATOR } = require("../db/utils")
|
const { DocumentTypes, SEPARATOR } = require("../db/utils")
|
||||||
|
const fs = require("fs")
|
||||||
|
const { cloneDeep } = require("lodash/fp")
|
||||||
|
|
||||||
const APP_PREFIX = DocumentTypes.APP + SEPARATOR
|
const APP_PREFIX = DocumentTypes.APP + SEPARATOR
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A map of how we convert various properties in rows to each other based on the row type.
|
||||||
|
*/
|
||||||
|
const TYPE_TRANSFORM_MAP = {
|
||||||
|
link: {
|
||||||
|
"": [],
|
||||||
|
[null]: [],
|
||||||
|
[undefined]: undefined,
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
"": "",
|
||||||
|
[null]: "",
|
||||||
|
[undefined]: undefined,
|
||||||
|
},
|
||||||
|
string: {
|
||||||
|
"": "",
|
||||||
|
[null]: "",
|
||||||
|
[undefined]: undefined,
|
||||||
|
},
|
||||||
|
longform: {
|
||||||
|
"": "",
|
||||||
|
[null]: "",
|
||||||
|
[undefined]: undefined,
|
||||||
|
},
|
||||||
|
number: {
|
||||||
|
"": null,
|
||||||
|
[null]: null,
|
||||||
|
[undefined]: undefined,
|
||||||
|
parse: n => parseFloat(n),
|
||||||
|
},
|
||||||
|
datetime: {
|
||||||
|
"": null,
|
||||||
|
[undefined]: undefined,
|
||||||
|
[null]: null,
|
||||||
|
},
|
||||||
|
attachment: {
|
||||||
|
"": [],
|
||||||
|
[null]: [],
|
||||||
|
[undefined]: undefined,
|
||||||
|
},
|
||||||
|
boolean: {
|
||||||
|
"": null,
|
||||||
|
[null]: null,
|
||||||
|
[undefined]: undefined,
|
||||||
|
true: true,
|
||||||
|
false: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
function confirmAppId(possibleAppId) {
|
function confirmAppId(possibleAppId) {
|
||||||
return possibleAppId && possibleAppId.startsWith(APP_PREFIX)
|
return possibleAppId && possibleAppId.startsWith(APP_PREFIX)
|
||||||
? possibleAppId
|
? possibleAppId
|
||||||
|
@ -74,3 +125,46 @@ exports.setCookie = (ctx, name, value) => {
|
||||||
exports.isClient = ctx => {
|
exports.isClient = ctx => {
|
||||||
return ctx.headers["x-budibase-type"] === "client"
|
return ctx.headers["x-budibase-type"] === "client"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively walk a directory tree and execute a callback on all files.
|
||||||
|
* @param {String} dirPath - Directory to traverse
|
||||||
|
* @param {Function} callback - callback to execute on files
|
||||||
|
*/
|
||||||
|
exports.walkDir = (dirPath, callback) => {
|
||||||
|
for (let filename of fs.readdirSync(dirPath)) {
|
||||||
|
const filePath = `${dirPath}/${filename}`
|
||||||
|
const stat = fs.lstatSync(filePath)
|
||||||
|
|
||||||
|
if (stat.isFile()) {
|
||||||
|
callback(filePath)
|
||||||
|
} else {
|
||||||
|
exports.walkDir(filePath, callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This will coerce the values in a row to the correct types based on the type transform map and the
|
||||||
|
* table schema.
|
||||||
|
* @param {object} row The row which is to be coerced to correct values based on schema, this input
|
||||||
|
* row will not be updated.
|
||||||
|
* @param {object} table The table that has been retrieved from DB, this must contain the expected
|
||||||
|
* schema for the rows.
|
||||||
|
* @returns {object} The updated row will be returned with all values coerced.
|
||||||
|
*/
|
||||||
|
exports.coerceRowValues = (row, table) => {
|
||||||
|
const clonedRow = cloneDeep(row)
|
||||||
|
for (let [key, value] of Object.entries(clonedRow)) {
|
||||||
|
const field = table.schema[key]
|
||||||
|
if (!field) continue
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-prototype-builtins
|
||||||
|
if (TYPE_TRANSFORM_MAP[field.type].hasOwnProperty(value)) {
|
||||||
|
clonedRow[key] = TYPE_TRANSFORM_MAP[field.type][value]
|
||||||
|
} else if (TYPE_TRANSFORM_MAP[field.type].parse) {
|
||||||
|
clonedRow[key] = TYPE_TRANSFORM_MAP[field.type].parse(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return clonedRow
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue