Merge pull request #13688 from Budibase/budi-8251-user-must-be-of-type-string
Fix - user must be of type string
This commit is contained in:
commit
9f2f177560
9 changed files with 58 additions and 42 deletions
|
@ -386,7 +386,7 @@
|
||||||
>
|
>
|
||||||
Hide column
|
Hide column
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
{#if $config.canEditColumns && column.schema.type === "link" && column.schema.tableId === TableNames.USERS}
|
{#if $config.canEditColumns && column.schema.type === "link" && column.schema.tableId === TableNames.USERS && !column.schema.autocolumn}
|
||||||
<MenuItem icon="User" on:click={openMigrationModal}>
|
<MenuItem icon="User" on:click={openMigrationModal}>
|
||||||
Migrate to user column
|
Migrate to user column
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
|
|
@ -265,7 +265,10 @@ export class ExternalRequest<T extends Operation> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inputProcessing(row: Row | undefined, table: Table) {
|
inputProcessing<T extends Row | undefined>(
|
||||||
|
row: T,
|
||||||
|
table: Table
|
||||||
|
): { row: T; manyRelationships: ManyRelationship[] } {
|
||||||
if (!row) {
|
if (!row) {
|
||||||
return { row, manyRelationships: [] }
|
return { row, manyRelationships: [] }
|
||||||
}
|
}
|
||||||
|
@ -346,7 +349,7 @@ export class ExternalRequest<T extends Operation> {
|
||||||
// we return the relationships that may need to be created in the through table
|
// we return the relationships that may need to be created in the through table
|
||||||
// we do this so that if the ID is generated by the DB it can be inserted
|
// we do this so that if the ID is generated by the DB it can be inserted
|
||||||
// after the fact
|
// after the fact
|
||||||
return { row: newRow, manyRelationships }
|
return { row: newRow as T, manyRelationships }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -598,6 +601,18 @@ export class ExternalRequest<T extends Operation> {
|
||||||
// clean up row on ingress using schema
|
// clean up row on ingress using schema
|
||||||
const processed = this.inputProcessing(row, table)
|
const processed = this.inputProcessing(row, table)
|
||||||
row = processed.row
|
row = processed.row
|
||||||
|
let manyRelationships = processed.manyRelationships
|
||||||
|
|
||||||
|
if (!row && rows) {
|
||||||
|
manyRelationships = []
|
||||||
|
for (let i = 0; i < rows.length; i++) {
|
||||||
|
const processed = this.inputProcessing(rows[i], table)
|
||||||
|
rows[i] = processed.row
|
||||||
|
if (processed.manyRelationships.length) {
|
||||||
|
manyRelationships.push(...processed.manyRelationships)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
operation === Operation.DELETE &&
|
operation === Operation.DELETE &&
|
||||||
(filters == null || Object.keys(filters).length === 0)
|
(filters == null || Object.keys(filters).length === 0)
|
||||||
|
|
|
@ -15,6 +15,7 @@ import {
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import sdk from "../../../sdk"
|
import sdk from "../../../sdk"
|
||||||
import { builderSocket } from "../../../websockets"
|
import { builderSocket } from "../../../websockets"
|
||||||
|
import { inputProcessing } from "../../../utilities/rowProcessor"
|
||||||
|
|
||||||
function getDatasourceId(table: Table) {
|
function getDatasourceId(table: Table) {
|
||||||
if (!table) {
|
if (!table) {
|
||||||
|
@ -80,7 +81,7 @@ export async function destroy(ctx: UserCtx) {
|
||||||
export async function bulkImport(
|
export async function bulkImport(
|
||||||
ctx: UserCtx<BulkImportRequest, BulkImportResponse>
|
ctx: UserCtx<BulkImportRequest, BulkImportResponse>
|
||||||
) {
|
) {
|
||||||
const table = await sdk.tables.getTable(ctx.params.tableId)
|
let table = await sdk.tables.getTable(ctx.params.tableId)
|
||||||
const { rows } = ctx.request.body
|
const { rows } = ctx.request.body
|
||||||
const schema = table.schema
|
const schema = table.schema
|
||||||
|
|
||||||
|
@ -88,7 +89,15 @@ export async function bulkImport(
|
||||||
ctx.throw(400, "Provided data import information is invalid.")
|
ctx.throw(400, "Provided data import information is invalid.")
|
||||||
}
|
}
|
||||||
|
|
||||||
const parsedRows = parse(rows, schema)
|
const parsedRows = []
|
||||||
|
for (const row of parse(rows, schema)) {
|
||||||
|
const processed = await inputProcessing(ctx.user?._id, table, row, {
|
||||||
|
noAutoRelationships: true,
|
||||||
|
})
|
||||||
|
parsedRows.push(processed.row)
|
||||||
|
table = processed.table
|
||||||
|
}
|
||||||
|
|
||||||
await handleRequest(Operation.BULK_CREATE, table._id!, {
|
await handleRequest(Operation.BULK_CREATE, table._id!, {
|
||||||
rows: parsedRows,
|
rows: parsedRows,
|
||||||
})
|
})
|
||||||
|
|
|
@ -79,9 +79,7 @@ export async function search(
|
||||||
}
|
}
|
||||||
|
|
||||||
const table = await sdk.tables.getTable(options.tableId)
|
const table = await sdk.tables.getTable(options.tableId)
|
||||||
options = searchInputMapping(table, options, {
|
options = searchInputMapping(table, options)
|
||||||
isSql: !!table.sql || !!env.SQS_SEARCH_ENABLE,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (isExternalTable) {
|
if (isExternalTable) {
|
||||||
return external.search(options, table)
|
return external.search(options, table)
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {
|
||||||
RowSearchParams,
|
RowSearchParams,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import { db as dbCore, context } from "@budibase/backend-core"
|
import { db as dbCore, context } from "@budibase/backend-core"
|
||||||
import { helpers, utils } from "@budibase/shared-core"
|
import { utils } from "@budibase/shared-core"
|
||||||
|
|
||||||
export async function paginatedSearch(
|
export async function paginatedSearch(
|
||||||
query: SearchFilters,
|
query: SearchFilters,
|
||||||
|
@ -49,12 +49,7 @@ function findColumnInQueries(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function userColumnMapping(
|
function userColumnMapping(column: string, options: RowSearchParams) {
|
||||||
column: string,
|
|
||||||
options: RowSearchParams,
|
|
||||||
isDeprecatedSingleUserColumn: boolean = false,
|
|
||||||
isSql: boolean = false
|
|
||||||
) {
|
|
||||||
findColumnInQueries(column, options, (filterValue: any): any => {
|
findColumnInQueries(column, options, (filterValue: any): any => {
|
||||||
const isArray = Array.isArray(filterValue),
|
const isArray = Array.isArray(filterValue),
|
||||||
isString = typeof filterValue === "string"
|
isString = typeof filterValue === "string"
|
||||||
|
@ -71,33 +66,23 @@ function userColumnMapping(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let wrapper = (s: string) => s
|
|
||||||
if (isDeprecatedSingleUserColumn && filterValue && isSql) {
|
|
||||||
// Decreated single users are stored as stringified arrays of a single value
|
|
||||||
wrapper = (s: string) => JSON.stringify([s])
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isArray) {
|
if (isArray) {
|
||||||
return filterValue.map(el => {
|
return filterValue.map(el => {
|
||||||
if (typeof el === "string") {
|
if (typeof el === "string") {
|
||||||
return wrapper(processString(el))
|
return processString(el)
|
||||||
} else {
|
} else {
|
||||||
return el
|
return el
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
return wrapper(processString(filterValue))
|
return processString(filterValue)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// maps through the search parameters to check if any of the inputs are invalid
|
// maps through the search parameters to check if any of the inputs are invalid
|
||||||
// based on the table schema, converts them to something that is valid.
|
// based on the table schema, converts them to something that is valid.
|
||||||
export function searchInputMapping(
|
export function searchInputMapping(table: Table, options: RowSearchParams) {
|
||||||
table: Table,
|
|
||||||
options: RowSearchParams,
|
|
||||||
datasourceOptions: { isSql?: boolean } = {}
|
|
||||||
) {
|
|
||||||
if (!table?.schema) {
|
if (!table?.schema) {
|
||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
|
@ -116,12 +101,7 @@ export function searchInputMapping(
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case FieldType.BB_REFERENCE: {
|
case FieldType.BB_REFERENCE: {
|
||||||
userColumnMapping(
|
userColumnMapping(key, options)
|
||||||
key,
|
|
||||||
options,
|
|
||||||
helpers.schema.isDeprecatedSingleUserColumn(column),
|
|
||||||
datasourceOptions.isSql
|
|
||||||
)
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,13 @@ export async function processInputBBReference(
|
||||||
subtype: BBReferenceFieldSubType.USER
|
subtype: BBReferenceFieldSubType.USER
|
||||||
): Promise<string | null> {
|
): Promise<string | null> {
|
||||||
if (value && Array.isArray(value)) {
|
if (value && Array.isArray(value)) {
|
||||||
throw "BB_REFERENCE_SINGLE cannot be an array"
|
if (value.length > 1) {
|
||||||
|
throw new InvalidBBRefError(
|
||||||
|
JSON.stringify(value),
|
||||||
|
BBReferenceFieldSubType.USER
|
||||||
|
)
|
||||||
|
}
|
||||||
|
value = value[0]
|
||||||
}
|
}
|
||||||
let id = typeof value === "string" ? value : value?._id
|
let id = typeof value === "string" ? value : value?._id
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ import {
|
||||||
processOutputBBReferences,
|
processOutputBBReferences,
|
||||||
} from "./bbReferenceProcessor"
|
} from "./bbReferenceProcessor"
|
||||||
import { isExternalTableID } from "../../integrations/utils"
|
import { isExternalTableID } from "../../integrations/utils"
|
||||||
|
import { helpers } from "@budibase/shared-core"
|
||||||
|
|
||||||
export * from "./utils"
|
export * from "./utils"
|
||||||
export * from "./attachments"
|
export * from "./attachments"
|
||||||
|
@ -162,10 +163,14 @@ export async function inputProcessing(
|
||||||
if (attachment?.url) {
|
if (attachment?.url) {
|
||||||
delete clonedRow[key].url
|
delete clonedRow[key].url
|
||||||
}
|
}
|
||||||
} else if (field.type === FieldType.BB_REFERENCE && value) {
|
} else if (
|
||||||
clonedRow[key] = await processInputBBReferences(value, field.subtype)
|
value &&
|
||||||
} else if (field.type === FieldType.BB_REFERENCE_SINGLE && value) {
|
(field.type === FieldType.BB_REFERENCE_SINGLE ||
|
||||||
|
helpers.schema.isDeprecatedSingleUserColumn(field))
|
||||||
|
) {
|
||||||
clonedRow[key] = await processInputBBReference(value, field.subtype)
|
clonedRow[key] = await processInputBBReference(value, field.subtype)
|
||||||
|
} else if (value && field.type === FieldType.BB_REFERENCE) {
|
||||||
|
clonedRow[key] = await processInputBBReferences(value, field.subtype)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -102,7 +102,7 @@ describe("rowProcessor - inputProcessing", () => {
|
||||||
name: "user",
|
name: "user",
|
||||||
constraints: {
|
constraints: {
|
||||||
presence: true,
|
presence: true,
|
||||||
type: "string",
|
type: "array",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -154,7 +154,7 @@ describe("rowProcessor - inputProcessing", () => {
|
||||||
name: "user",
|
name: "user",
|
||||||
constraints: {
|
constraints: {
|
||||||
presence: false,
|
presence: false,
|
||||||
type: "string",
|
type: "array",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -196,7 +196,7 @@ describe("rowProcessor - inputProcessing", () => {
|
||||||
name: "user",
|
name: "user",
|
||||||
constraints: {
|
constraints: {
|
||||||
presence: false,
|
presence: false,
|
||||||
type: "string",
|
type: "array",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -6,7 +6,10 @@ import {
|
||||||
|
|
||||||
export function isDeprecatedSingleUserColumn(
|
export function isDeprecatedSingleUserColumn(
|
||||||
schema: Pick<FieldSchema, "type" | "subtype" | "constraints">
|
schema: Pick<FieldSchema, "type" | "subtype" | "constraints">
|
||||||
) {
|
): schema is {
|
||||||
|
type: FieldType.BB_REFERENCE
|
||||||
|
subtype: BBReferenceFieldSubType.USER
|
||||||
|
} {
|
||||||
const result =
|
const result =
|
||||||
schema.type === FieldType.BB_REFERENCE &&
|
schema.type === FieldType.BB_REFERENCE &&
|
||||||
schema.subtype === BBReferenceFieldSubType.USER &&
|
schema.subtype === BBReferenceFieldSubType.USER &&
|
||||||
|
|
Loading…
Reference in a new issue