Merge pull request #15209 from Budibase/chore/guard-display-column-in-the-api
Guard display column in the api
This commit is contained in:
commit
bbd69ce318
|
@ -37,6 +37,7 @@ import { jsonFromCsvString } from "../../../utilities/csv"
|
||||||
import { builderSocket } from "../../../websockets"
|
import { builderSocket } from "../../../websockets"
|
||||||
import { cloneDeep } from "lodash"
|
import { cloneDeep } from "lodash"
|
||||||
import {
|
import {
|
||||||
|
canBeDisplayColumn,
|
||||||
helpers,
|
helpers,
|
||||||
PROTECTED_EXTERNAL_COLUMNS,
|
PROTECTED_EXTERNAL_COLUMNS,
|
||||||
PROTECTED_INTERNAL_COLUMNS,
|
PROTECTED_INTERNAL_COLUMNS,
|
||||||
|
@ -67,6 +68,27 @@ function checkDefaultFields(table: Table) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function guardTable(table: Table, isCreate: boolean) {
|
||||||
|
checkDefaultFields(table)
|
||||||
|
|
||||||
|
if (
|
||||||
|
table.primaryDisplay &&
|
||||||
|
!canBeDisplayColumn(table.schema[table.primaryDisplay]?.type)
|
||||||
|
) {
|
||||||
|
// Prevent throwing errors from existing badly configured tables. Only throw for new tables or if this setting is being updated
|
||||||
|
if (
|
||||||
|
isCreate ||
|
||||||
|
(await sdk.tables.getTable(table._id!)).primaryDisplay !==
|
||||||
|
table.primaryDisplay
|
||||||
|
) {
|
||||||
|
throw new HTTPError(
|
||||||
|
`Column "${table.primaryDisplay}" cannot be used as a display type.`,
|
||||||
|
400
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// covers both internal and external
|
// covers both internal and external
|
||||||
export async function fetch(ctx: UserCtx<void, FetchTablesResponse>) {
|
export async function fetch(ctx: UserCtx<void, FetchTablesResponse>) {
|
||||||
const internal = await sdk.tables.getAllInternalTables()
|
const internal = await sdk.tables.getAllInternalTables()
|
||||||
|
@ -111,7 +133,7 @@ export async function save(ctx: UserCtx<SaveTableRequest, SaveTableResponse>) {
|
||||||
|
|
||||||
const isCreate = !table._id
|
const isCreate = !table._id
|
||||||
|
|
||||||
checkDefaultFields(table)
|
await guardTable(table, isCreate)
|
||||||
|
|
||||||
let savedTable: Table
|
let savedTable: Table
|
||||||
if (isCreate) {
|
if (isCreate) {
|
||||||
|
|
|
@ -3399,7 +3399,7 @@ if (descriptions.length) {
|
||||||
type: FieldType.LINK,
|
type: FieldType.LINK,
|
||||||
relationshipType: RelationshipType.MANY_TO_ONE,
|
relationshipType: RelationshipType.MANY_TO_ONE,
|
||||||
tableId: toRelateTableId,
|
tableId: toRelateTableId,
|
||||||
fieldName: "link",
|
fieldName: "main",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -3408,7 +3408,7 @@ if (descriptions.length) {
|
||||||
)
|
)
|
||||||
await config.api.table.save({
|
await config.api.table.save({
|
||||||
...toRelateTable,
|
...toRelateTable,
|
||||||
primaryDisplay: "link",
|
primaryDisplay: "name",
|
||||||
})
|
})
|
||||||
const relatedRows = await Promise.all([
|
const relatedRows = await Promise.all([
|
||||||
config.api.row.save(toRelateTable._id!, {
|
config.api.row.save(toRelateTable._id!, {
|
||||||
|
|
|
@ -185,6 +185,62 @@ if (descriptions.length) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
it("can set primary display", async () => {
|
||||||
|
const columnName = generator.word()
|
||||||
|
const table = await config.api.table.save(
|
||||||
|
tableForDatasource(datasource, {
|
||||||
|
primaryDisplay: columnName,
|
||||||
|
schema: {
|
||||||
|
[columnName]: {
|
||||||
|
name: columnName,
|
||||||
|
type: FieldType.STRING,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
)
|
||||||
|
expect(table.primaryDisplay).toEqual(columnName)
|
||||||
|
|
||||||
|
const res = await config.api.table.get(table._id!)
|
||||||
|
expect(res.primaryDisplay).toEqual(columnName)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("cannot use unexisting columns as primary display", async () => {
|
||||||
|
const columnName = generator.word()
|
||||||
|
await config.api.table.save(
|
||||||
|
tableForDatasource(datasource, {
|
||||||
|
primaryDisplay: columnName,
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
status: 400,
|
||||||
|
body: {
|
||||||
|
message: `Column "${columnName}" cannot be used as a display type.`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("cannot use invalid column types as display name", async () => {
|
||||||
|
const columnName = generator.word()
|
||||||
|
|
||||||
|
await config.api.table.save(
|
||||||
|
tableForDatasource(datasource, {
|
||||||
|
primaryDisplay: columnName,
|
||||||
|
schema: {
|
||||||
|
[columnName]: {
|
||||||
|
name: columnName,
|
||||||
|
type: FieldType.BOOLEAN,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
status: 400,
|
||||||
|
body: {
|
||||||
|
message: `Column "${columnName}" cannot be used as a display type.`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("permissions", () => {
|
describe("permissions", () => {
|
||||||
|
@ -603,6 +659,49 @@ if (descriptions.length) {
|
||||||
}
|
}
|
||||||
expect(response).toEqual(expectedResponse)
|
expect(response).toEqual(expectedResponse)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("cannot use unexisting columns as primary display", async () => {
|
||||||
|
const table = await config.api.table.save(
|
||||||
|
tableForDatasource(datasource)
|
||||||
|
)
|
||||||
|
|
||||||
|
const columnName = generator.word()
|
||||||
|
const tableRequest = {
|
||||||
|
...table,
|
||||||
|
primaryDisplay: columnName,
|
||||||
|
}
|
||||||
|
await config.api.table.save(tableRequest, {
|
||||||
|
status: 400,
|
||||||
|
body: {
|
||||||
|
message: `Column "${columnName}" cannot be used as a display type.`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("cannot use invalid column types as display name", async () => {
|
||||||
|
const table = await config.api.table.save(
|
||||||
|
tableForDatasource(datasource)
|
||||||
|
)
|
||||||
|
const columnName = generator.word()
|
||||||
|
const tableRequest: SaveTableRequest = {
|
||||||
|
...table,
|
||||||
|
primaryDisplay: columnName,
|
||||||
|
schema: {
|
||||||
|
...table.schema,
|
||||||
|
[columnName]: {
|
||||||
|
name: columnName,
|
||||||
|
type: FieldType.BOOLEAN,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
await config.api.table.save(tableRequest, {
|
||||||
|
status: 400,
|
||||||
|
body: {
|
||||||
|
message: `Column "${columnName}" cannot be used as a display type.`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("import", () => {
|
describe("import", () => {
|
||||||
|
|
|
@ -12,8 +12,8 @@ const allowDisplayColumnByType: Record<FieldType, boolean> = {
|
||||||
[FieldType.AUTO]: true,
|
[FieldType.AUTO]: true,
|
||||||
[FieldType.INTERNAL]: true,
|
[FieldType.INTERNAL]: true,
|
||||||
[FieldType.BARCODEQR]: true,
|
[FieldType.BARCODEQR]: true,
|
||||||
|
|
||||||
[FieldType.BIGINT]: true,
|
[FieldType.BIGINT]: true,
|
||||||
|
|
||||||
[FieldType.BOOLEAN]: false,
|
[FieldType.BOOLEAN]: false,
|
||||||
[FieldType.ARRAY]: false,
|
[FieldType.ARRAY]: false,
|
||||||
[FieldType.ATTACHMENTS]: false,
|
[FieldType.ATTACHMENTS]: false,
|
||||||
|
|
Loading…
Reference in New Issue