Merge pull request #15209 from Budibase/chore/guard-display-column-in-the-api

Guard display column in the api
This commit is contained in:
Adria Navarro 2024-12-19 12:30:16 +01:00 committed by GitHub
commit bbd69ce318
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 125 additions and 4 deletions

View File

@ -37,6 +37,7 @@ import { jsonFromCsvString } from "../../../utilities/csv"
import { builderSocket } from "../../../websockets"
import { cloneDeep } from "lodash"
import {
canBeDisplayColumn,
helpers,
PROTECTED_EXTERNAL_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
export async function fetch(ctx: UserCtx<void, FetchTablesResponse>) {
const internal = await sdk.tables.getAllInternalTables()
@ -111,7 +133,7 @@ export async function save(ctx: UserCtx<SaveTableRequest, SaveTableResponse>) {
const isCreate = !table._id
checkDefaultFields(table)
await guardTable(table, isCreate)
let savedTable: Table
if (isCreate) {

View File

@ -3399,7 +3399,7 @@ if (descriptions.length) {
type: FieldType.LINK,
relationshipType: RelationshipType.MANY_TO_ONE,
tableId: toRelateTableId,
fieldName: "link",
fieldName: "main",
},
})
@ -3408,7 +3408,7 @@ if (descriptions.length) {
)
await config.api.table.save({
...toRelateTable,
primaryDisplay: "link",
primaryDisplay: "name",
})
const relatedRows = await Promise.all([
config.api.row.save(toRelateTable._id!, {

View File

@ -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", () => {
@ -603,6 +659,49 @@ if (descriptions.length) {
}
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", () => {

View File

@ -12,8 +12,8 @@ const allowDisplayColumnByType: Record<FieldType, boolean> = {
[FieldType.AUTO]: true,
[FieldType.INTERNAL]: true,
[FieldType.BARCODEQR]: true,
[FieldType.BIGINT]: true,
[FieldType.BOOLEAN]: false,
[FieldType.ARRAY]: false,
[FieldType.ATTACHMENTS]: false,