Merge branch 'master' of github.com:Budibase/budibase into form-builder
This commit is contained in:
commit
3206b8dc14
|
@ -9,7 +9,7 @@ const {
|
||||||
ViewNames,
|
ViewNames,
|
||||||
} = require("../../db/utils")
|
} = require("../../db/utils")
|
||||||
const usersController = require("./user")
|
const usersController = require("./user")
|
||||||
const { coerceRowValues } = require("../../utilities")
|
const { coerceRowValues, enrichRows } = require("../../utilities")
|
||||||
|
|
||||||
const TABLE_VIEW_BEGINS_WITH = `all${SEPARATOR}${DocumentTypes.TABLE}${SEPARATOR}`
|
const TABLE_VIEW_BEGINS_WITH = `all${SEPARATOR}${DocumentTypes.TABLE}${SEPARATOR}`
|
||||||
|
|
||||||
|
@ -190,7 +190,15 @@ exports.fetchView = async function(ctx) {
|
||||||
|
|
||||||
if (!calculation) {
|
if (!calculation) {
|
||||||
response.rows = response.rows.map(row => row.doc)
|
response.rows = response.rows.map(row => row.doc)
|
||||||
ctx.body = await linkRows.attachLinkInfo(appId, response.rows)
|
let table
|
||||||
|
try {
|
||||||
|
table = await db.get(ctx.params.tableId)
|
||||||
|
} catch (err) {
|
||||||
|
table = {
|
||||||
|
schema: {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.body = await enrichRows(appId, table, response.rows)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (calculation === CALCULATION_TYPES.STATS) {
|
if (calculation === CALCULATION_TYPES.STATS) {
|
||||||
|
@ -217,14 +225,15 @@ exports.fetchView = async function(ctx) {
|
||||||
|
|
||||||
exports.fetchTableRows = async function(ctx) {
|
exports.fetchTableRows = async function(ctx) {
|
||||||
const appId = ctx.user.appId
|
const appId = ctx.user.appId
|
||||||
|
const db = new CouchDB(appId)
|
||||||
|
|
||||||
// special case for users, fetch through the user controller
|
// special case for users, fetch through the user controller
|
||||||
let rows
|
let rows,
|
||||||
|
table = await db.get(ctx.params.tableId)
|
||||||
if (ctx.params.tableId === ViewNames.USERS) {
|
if (ctx.params.tableId === ViewNames.USERS) {
|
||||||
await usersController.fetch(ctx)
|
await usersController.fetch(ctx)
|
||||||
rows = ctx.body
|
rows = ctx.body
|
||||||
} else {
|
} else {
|
||||||
const db = new CouchDB(appId)
|
|
||||||
const response = await db.allDocs(
|
const response = await db.allDocs(
|
||||||
getRowParams(ctx.params.tableId, null, {
|
getRowParams(ctx.params.tableId, null, {
|
||||||
include_docs: true,
|
include_docs: true,
|
||||||
|
@ -232,15 +241,16 @@ exports.fetchTableRows = async function(ctx) {
|
||||||
)
|
)
|
||||||
rows = response.rows.map(row => row.doc)
|
rows = response.rows.map(row => row.doc)
|
||||||
}
|
}
|
||||||
ctx.body = await linkRows.attachLinkInfo(appId, rows)
|
ctx.body = await enrichRows(appId, table, rows)
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
try {
|
try {
|
||||||
|
const table = await db.get(ctx.params.tableId)
|
||||||
const row = await findRow(db, appId, ctx.params.tableId, ctx.params.rowId)
|
const row = await findRow(db, appId, ctx.params.tableId, ctx.params.rowId)
|
||||||
ctx.body = await linkRows.attachLinkInfo(appId, row)
|
ctx.body = await enrichRows(appId, table, row)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
ctx.throw(400, err)
|
ctx.throw(400, err)
|
||||||
}
|
}
|
||||||
|
@ -325,8 +335,9 @@ exports.fetchEnrichedRow = async function(ctx) {
|
||||||
keys: linkVals.map(linkVal => linkVal.id),
|
keys: linkVals.map(linkVal => linkVal.id),
|
||||||
})
|
})
|
||||||
// need to include the IDs in these rows for any links they may have
|
// need to include the IDs in these rows for any links they may have
|
||||||
let linkedRows = await linkRows.attachLinkInfo(
|
let linkedRows = await enrichRows(
|
||||||
appId,
|
appId,
|
||||||
|
table,
|
||||||
response.rows.map(row => row.doc)
|
response.rows.map(row => row.doc)
|
||||||
)
|
)
|
||||||
// insert the link rows in the correct place throughout the main row
|
// insert the link rows in the correct place throughout the main row
|
||||||
|
|
|
@ -17,11 +17,12 @@ const CouchDB = require("../../../db")
|
||||||
const setBuilderToken = require("../../../utilities/builder/setBuilderToken")
|
const setBuilderToken = require("../../../utilities/builder/setBuilderToken")
|
||||||
const fileProcessor = require("../../../utilities/fileProcessor")
|
const fileProcessor = require("../../../utilities/fileProcessor")
|
||||||
const env = require("../../../environment")
|
const env = require("../../../environment")
|
||||||
|
const { OBJ_STORE_DIRECTORY } = require("../../../constants")
|
||||||
|
|
||||||
function objectStoreUrl() {
|
function objectStoreUrl() {
|
||||||
if (env.SELF_HOSTED) {
|
if (env.SELF_HOSTED) {
|
||||||
// can use a relative url for this as all goes through the proxy (this is hosted in minio)
|
// can use a relative url for this as all goes through the proxy (this is hosted in minio)
|
||||||
return `/app-assets/assets`
|
return OBJ_STORE_DIRECTORY
|
||||||
} else {
|
} else {
|
||||||
return "https://cdn.app.budi.live/assets"
|
return "https://cdn.app.budi.live/assets"
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,7 +108,7 @@ exports.save = async function(ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// update linked rows
|
// update linked rows
|
||||||
await linkRows.updateLinks({
|
const linkResp = await linkRows.updateLinks({
|
||||||
appId,
|
appId,
|
||||||
eventType: oldTable
|
eventType: oldTable
|
||||||
? linkRows.EventType.TABLE_UPDATED
|
? linkRows.EventType.TABLE_UPDATED
|
||||||
|
@ -116,6 +116,9 @@ exports.save = async function(ctx) {
|
||||||
table: tableToSave,
|
table: tableToSave,
|
||||||
oldTable: oldTable,
|
oldTable: oldTable,
|
||||||
})
|
})
|
||||||
|
if (linkResp != null && linkResp._rev) {
|
||||||
|
tableToSave._rev = linkResp._rev
|
||||||
|
}
|
||||||
|
|
||||||
// don't perform any updates until relationships have been
|
// don't perform any updates until relationships have been
|
||||||
// checked by the updateLinks function
|
// checked by the updateLinks function
|
||||||
|
|
|
@ -37,29 +37,31 @@ exports.defaultHeaders = appId => {
|
||||||
return headers
|
return headers
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.createTable = async (request, appId, table) => {
|
exports.BASE_TABLE = {
|
||||||
if (table != null && table._id) {
|
name: "TestTable",
|
||||||
delete table._id
|
type: "table",
|
||||||
}
|
key: "name",
|
||||||
table = table || {
|
schema: {
|
||||||
name: "TestTable",
|
name: {
|
||||||
type: "table",
|
type: "string",
|
||||||
key: "name",
|
constraints: {
|
||||||
schema: {
|
|
||||||
name: {
|
|
||||||
type: "string",
|
type: "string",
|
||||||
constraints: {
|
|
||||||
type: "string",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
description: {
|
|
||||||
type: "string",
|
|
||||||
constraints: {
|
|
||||||
type: "string",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: {
|
||||||
|
type: "string",
|
||||||
|
constraints: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.createTable = async (request, appId, table, removeId = true) => {
|
||||||
|
if (removeId && table != null && table._id) {
|
||||||
|
delete table._id
|
||||||
}
|
}
|
||||||
|
table = table || exports.BASE_TABLE
|
||||||
|
|
||||||
const res = await request
|
const res = await request
|
||||||
.post(`/api/tables`)
|
.post(`/api/tables`)
|
||||||
|
@ -68,6 +70,25 @@ exports.createTable = async (request, appId, table) => {
|
||||||
return res.body
|
return res.body
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exports.createLinkedTable = async (request, appId) => {
|
||||||
|
// get the ID to link to
|
||||||
|
const table = await exports.createTable(request, appId)
|
||||||
|
table.schema.link = {
|
||||||
|
type: "link",
|
||||||
|
fieldName: "link",
|
||||||
|
tableId: table._id,
|
||||||
|
}
|
||||||
|
return exports.createTable(request, appId, table, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.createAttachmentTable = async (request, appId) => {
|
||||||
|
const table = await exports.createTable(request, appId)
|
||||||
|
table.schema.attachment = {
|
||||||
|
type: "attachment",
|
||||||
|
}
|
||||||
|
return exports.createTable(request, appId, table, false)
|
||||||
|
}
|
||||||
|
|
||||||
exports.getAllFromTable = async (request, appId, tableId) => {
|
exports.getAllFromTable = async (request, appId, tableId) => {
|
||||||
const res = await request
|
const res = await request
|
||||||
.get(`/api/${tableId}/rows`)
|
.get(`/api/${tableId}/rows`)
|
||||||
|
|
|
@ -3,7 +3,11 @@ const {
|
||||||
createTable,
|
createTable,
|
||||||
supertest,
|
supertest,
|
||||||
defaultHeaders,
|
defaultHeaders,
|
||||||
|
createLinkedTable,
|
||||||
|
createAttachmentTable,
|
||||||
} = require("./couchTestUtils");
|
} = require("./couchTestUtils");
|
||||||
|
const { enrichRows } = require("../../../utilities")
|
||||||
|
const env = require("../../../environment")
|
||||||
|
|
||||||
describe("/rows", () => {
|
describe("/rows", () => {
|
||||||
let request
|
let request
|
||||||
|
@ -270,4 +274,44 @@ describe("/rows", () => {
|
||||||
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("enrich row unit test", () => {
|
||||||
|
it("should allow enriching some linked rows", async () => {
|
||||||
|
const table = await createLinkedTable(request, appId)
|
||||||
|
const firstRow = (await createRow({
|
||||||
|
name: "Test Contact",
|
||||||
|
description: "original description",
|
||||||
|
tableId: table._id
|
||||||
|
})).body
|
||||||
|
const secondRow = (await createRow({
|
||||||
|
name: "Test 2",
|
||||||
|
description: "og desc",
|
||||||
|
link: [firstRow._id],
|
||||||
|
tableId: table._id,
|
||||||
|
})).body
|
||||||
|
const enriched = await enrichRows(appId, table, [secondRow])
|
||||||
|
expect(enriched[0].link.length).toBe(1)
|
||||||
|
expect(enriched[0].link[0]).toBe(firstRow._id)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should allow enriching attachment rows", async () => {
|
||||||
|
const table = await createAttachmentTable(request, appId)
|
||||||
|
const row = (await createRow({
|
||||||
|
name: "test",
|
||||||
|
description: "test",
|
||||||
|
attachment: [{
|
||||||
|
url: "/test/thing",
|
||||||
|
}],
|
||||||
|
tableId: table._id,
|
||||||
|
})).body
|
||||||
|
// the environment needs configured for this
|
||||||
|
env.CLOUD = 1
|
||||||
|
env.SELF_HOSTED = 1
|
||||||
|
const enriched = await enrichRows(appId, table, [row])
|
||||||
|
expect(enriched[0].attachment[0].url).toBe(`/app-assets/assets/${appId}/test/thing`)
|
||||||
|
// remove env config
|
||||||
|
env.CLOUD = undefined
|
||||||
|
env.SELF_HOSTED = undefined
|
||||||
|
})
|
||||||
})
|
})
|
|
@ -43,3 +43,4 @@ exports.AuthTypes = AuthTypes
|
||||||
exports.USERS_TABLE_SCHEMA = USERS_TABLE_SCHEMA
|
exports.USERS_TABLE_SCHEMA = USERS_TABLE_SCHEMA
|
||||||
exports.BUILDER_CONFIG_DB = "builder-config-db"
|
exports.BUILDER_CONFIG_DB = "builder-config-db"
|
||||||
exports.HOSTING_DOC = "hosting-doc"
|
exports.HOSTING_DOC = "hosting-doc"
|
||||||
|
exports.OBJ_STORE_DIRECTORY = "/app-assets/assets"
|
||||||
|
|
|
@ -252,7 +252,11 @@ class LinkController {
|
||||||
tableId: table._id,
|
tableId: table._id,
|
||||||
fieldName: fieldName,
|
fieldName: fieldName,
|
||||||
}
|
}
|
||||||
await this._db.put(linkedTable)
|
const response = await this._db.put(linkedTable)
|
||||||
|
// special case for when linking back to self, make sure rev updated
|
||||||
|
if (linkedTable._id === table._id) {
|
||||||
|
table._rev = response.rev
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return table
|
return table
|
||||||
|
|
|
@ -31,11 +31,14 @@ exports.createLinkView = async appId => {
|
||||||
thisId: doc1.rowId,
|
thisId: doc1.rowId,
|
||||||
fieldName: doc1.fieldName,
|
fieldName: doc1.fieldName,
|
||||||
})
|
})
|
||||||
emit([doc2.tableId, doc2.rowId], {
|
// if linking to same table can't emit twice
|
||||||
id: doc1.rowId,
|
if (doc1.tableId !== doc2.tableId) {
|
||||||
thisId: doc2.rowId,
|
emit([doc2.tableId, doc2.rowId], {
|
||||||
fieldName: doc2.fieldName,
|
id: doc1.rowId,
|
||||||
})
|
thisId: doc2.rowId,
|
||||||
|
fieldName: doc2.fieldName,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}.toString(),
|
}.toString(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@ const { DocumentTypes, SEPARATOR } = require("../db/utils")
|
||||||
const fs = require("fs")
|
const fs = require("fs")
|
||||||
const { cloneDeep } = require("lodash/fp")
|
const { cloneDeep } = require("lodash/fp")
|
||||||
const CouchDB = require("../db")
|
const CouchDB = require("../db")
|
||||||
|
const { OBJ_STORE_DIRECTORY } = require("../constants")
|
||||||
|
const linkRows = require("../db/linkedRows")
|
||||||
|
|
||||||
const APP_PREFIX = DocumentTypes.APP + SEPARATOR
|
const APP_PREFIX = DocumentTypes.APP + SEPARATOR
|
||||||
|
|
||||||
|
@ -211,3 +213,34 @@ exports.getAllApps = async () => {
|
||||||
.map(({ value }) => value)
|
.map(({ value }) => value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function "enriches" the input rows with anything they are supposed to contain, for example
|
||||||
|
* link records or attachment links.
|
||||||
|
* @param {string} appId the ID of the application for which rows are being enriched.
|
||||||
|
* @param {object} table the table from which these rows came from originally, this is used to determine
|
||||||
|
* the schema of the rows and then enrich.
|
||||||
|
* @param {object[]} rows the rows which are to be enriched.
|
||||||
|
* @returns {object[]} the enriched rows will be returned.
|
||||||
|
*/
|
||||||
|
exports.enrichRows = async (appId, table, rows) => {
|
||||||
|
// attach any linked row information
|
||||||
|
const enriched = await linkRows.attachLinkInfo(appId, rows)
|
||||||
|
// update the attachments URL depending on hosting
|
||||||
|
if (env.CLOUD && env.SELF_HOSTED) {
|
||||||
|
for (let [property, column] of Object.entries(table.schema)) {
|
||||||
|
if (column.type === "attachment") {
|
||||||
|
for (let row of enriched) {
|
||||||
|
if (row[property] == null || row[property].length === 0) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
row[property].forEach(attachment => {
|
||||||
|
attachment.url = `${OBJ_STORE_DIRECTORY}/${appId}/${attachment.url}`
|
||||||
|
attachment.url = attachment.url.replace("//", "/")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return enriched
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue