diff --git a/packages/backend-core/src/objectStore/utils.ts b/packages/backend-core/src/objectStore/utils.ts
index 5b9c2e3646..30c2fefbf1 100644
--- a/packages/backend-core/src/objectStore/utils.ts
+++ b/packages/backend-core/src/objectStore/utils.ts
@@ -9,6 +9,9 @@ import {
AutomationAttachmentContent,
BucketedContent,
} from "@budibase/types"
+import stream from "stream"
+import streamWeb from "node:stream/web"
+
/****************************************************
* NOTE: When adding a new bucket - name *
* sure that S3 usages (like budibase-infra) *
@@ -53,12 +56,10 @@ export const bucketTTLConfig = (
Rules: [lifecycleRule],
}
- const params = {
+ return {
Bucket: bucketName,
LifecycleConfiguration: lifecycleConfiguration,
}
-
- return params
}
async function processUrlAttachment(
@@ -69,9 +70,12 @@ async function processUrlAttachment(
throw new Error(`Unexpected response ${response.statusText}`)
}
const fallbackFilename = path.basename(new URL(attachment.url).pathname)
+ if (!response.body) {
+ throw new Error("No response received for attachment")
+ }
return {
filename: attachment.filename || fallbackFilename,
- content: response.body,
+ content: stream.Readable.fromWeb(response.body as streamWeb.ReadableStream),
}
}
diff --git a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte
index 85af5bbafd..879927343f 100644
--- a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte
+++ b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte
@@ -374,6 +374,16 @@
return `${value.title || (key === "row" ? "Table" : key)} ${requiredSuffix}`
}
+ function handleAttachmentParams(keyValueObj) {
+ let params = {}
+ if (keyValueObj?.length) {
+ for (let param of keyValueObj) {
+ params[param.url] = param.filename
+ }
+ }
+ return params
+ }
+
onMount(async () => {
try {
await environment.loadVariables()
@@ -381,15 +391,6 @@
console.error(error)
}
})
- const handleAttachmentParams = keyValuObj => {
- let params = {}
- if (keyValuObj?.length) {
- for (let param of keyValuObj) {
- params[param.url] = param.filename
- }
- }
- return params
- }
diff --git a/packages/builder/src/components/automation/SetupPanel/RowSelectorTypes.svelte b/packages/builder/src/components/automation/SetupPanel/RowSelectorTypes.svelte
index 9b4e5e36f6..1b52e35314 100644
--- a/packages/builder/src/components/automation/SetupPanel/RowSelectorTypes.svelte
+++ b/packages/builder/src/components/automation/SetupPanel/RowSelectorTypes.svelte
@@ -25,21 +25,21 @@
return !!schema.constraints?.inclusion?.length
}
- const handleAttachmentParams = keyValuObj => {
+ function handleAttachmentParams(keyValueObj) {
let params = {}
if (
schema.type === FieldType.ATTACHMENT_SINGLE &&
- Object.keys(keyValuObj).length === 0
+ Object.keys(keyValueObj).length === 0
) {
return []
}
- if (!Array.isArray(keyValuObj)) {
- keyValuObj = [keyValuObj]
+ if (!Array.isArray(keyValueObj) && keyValueObj) {
+ keyValueObj = [keyValueObj]
}
- if (keyValuObj.length) {
- for (let param of keyValuObj) {
+ if (keyValueObj.length) {
+ for (let param of keyValueObj) {
params[param.url] = param.filename
}
}
diff --git a/packages/server/src/automations/automationUtils.ts b/packages/server/src/automations/automationUtils.ts
index c94c166be1..cb09f860da 100644
--- a/packages/server/src/automations/automationUtils.ts
+++ b/packages/server/src/automations/automationUtils.ts
@@ -163,7 +163,10 @@ async function generateAttachmentRow(attachment: AutomationAttachment) {
try {
const { filename } = attachment
- const extension = path.extname(filename)
+ let extension = path.extname(filename)
+ if (extension.startsWith(".")) {
+ extension = extension.substring(1, extension.length)
+ }
const attachmentResult = await objectStore.processAutomationAttachment(
attachment
)
@@ -182,8 +185,8 @@ async function generateAttachmentRow(attachment: AutomationAttachment) {
return {
size,
- name: filename,
extension,
+ name: filename,
key: s3Key,
}
} catch (error) {
diff --git a/packages/server/src/automations/steps/updateRow.ts b/packages/server/src/automations/steps/updateRow.ts
index 348c5e8373..32c8addd7a 100644
--- a/packages/server/src/automations/steps/updateRow.ts
+++ b/packages/server/src/automations/steps/updateRow.ts
@@ -94,18 +94,6 @@ export async function run({ inputs, appId, emitter }: AutomationStepInput) {
}
}
- // have to clean up the row, remove the table from it
- const ctx: any = buildCtx(appId, emitter, {
- body: {
- ...inputs.row,
- _id: inputs.rowId,
- },
- params: {
- rowId: inputs.rowId,
- tableId: tableId,
- },
- })
-
try {
if (tableId) {
inputs.row = await automationUtils.cleanUpRow(
@@ -118,6 +106,17 @@ export async function run({ inputs, appId, emitter }: AutomationStepInput) {
inputs.row
)
}
+ // have to clean up the row, remove the table from it
+ const ctx: any = buildCtx(appId, emitter, {
+ body: {
+ ...inputs.row,
+ _id: inputs.rowId,
+ },
+ params: {
+ rowId: inputs.rowId,
+ tableId: tableId,
+ },
+ })
await rowController.patch(ctx)
return {
row: ctx.body,
diff --git a/packages/server/src/utilities/rowProcessor/attachments.ts b/packages/server/src/utilities/rowProcessor/attachments.ts
index da52d6a631..bfa216c25b 100644
--- a/packages/server/src/utilities/rowProcessor/attachments.ts
+++ b/packages/server/src/utilities/rowProcessor/attachments.ts
@@ -1,6 +1,12 @@
import { ObjectStoreBuckets } from "../../constants"
import { context, db as dbCore, objectStore } from "@budibase/backend-core"
-import { FieldType, RenameColumn, Row, Table } from "@budibase/types"
+import {
+ FieldType,
+ RenameColumn,
+ Row,
+ RowAttachment,
+ Table,
+} from "@budibase/types"
export class AttachmentCleanup {
static async coreCleanup(fileListFn: () => string[]): Promise {
@@ -21,7 +27,7 @@ export class AttachmentCleanup {
private static extractAttachmentKeys(
type: FieldType,
- rowData: any
+ rowData: RowAttachment[] | RowAttachment
): string[] {
if (
type !== FieldType.ATTACHMENTS &&
@@ -34,10 +40,15 @@ export class AttachmentCleanup {
return []
}
- if (type === FieldType.ATTACHMENTS) {
- return rowData.map((attachment: any) => attachment.key)
+ if (type === FieldType.ATTACHMENTS && Array.isArray(rowData)) {
+ return rowData
+ .filter(attachment => attachment.key)
+ .map(attachment => attachment.key)
+ } else if ("key" in rowData) {
+ return [rowData.key]
}
- return [rowData.key]
+
+ return []
}
private static async tableChange(
diff --git a/packages/server/src/utilities/rowProcessor/index.ts b/packages/server/src/utilities/rowProcessor/index.ts
index b71f40e870..e7bc725285 100644
--- a/packages/server/src/utilities/rowProcessor/index.ts
+++ b/packages/server/src/utilities/rowProcessor/index.ts
@@ -1,11 +1,11 @@
import * as linkRows from "../../db/linkedRows"
-import { processFormulas, fixAutoColumnSubType } from "./utils"
+import { fixAutoColumnSubType, processFormulas } from "./utils"
import { objectStore, utils } from "@budibase/backend-core"
import { InternalTables } from "../../db/utils"
import { TYPE_TRANSFORM_MAP } from "./map"
import {
- FieldType,
AutoFieldSubType,
+ FieldType,
Row,
RowAttachment,
Table,
@@ -221,27 +221,31 @@ export async function outputProcessing(
opts.squash = true
}
- // process complex types: attachements, bb references...
+ // process complex types: attachments, bb references...
for (let [property, column] of Object.entries(table.schema)) {
- if (column.type === FieldType.ATTACHMENTS) {
+ if (
+ column.type === FieldType.ATTACHMENTS ||
+ column.type === FieldType.ATTACHMENT_SINGLE
+ ) {
for (let row of enriched) {
- if (row[property] == null || !Array.isArray(row[property])) {
+ if (row[property] == null) {
continue
}
- row[property].forEach((attachment: RowAttachment) => {
- if (!attachment.url) {
+ const process = (attachment: RowAttachment) => {
+ if (!attachment.url && attachment.key) {
attachment.url = objectStore.getAppFileUrl(attachment.key)
}
- })
- }
- } else if (column.type === FieldType.ATTACHMENT_SINGLE) {
- for (let row of enriched) {
- if (!row[property] || Object.keys(row[property]).length === 0) {
- continue
+ return attachment
}
-
- if (!row[property].url) {
- row[property].url = objectStore.getAppFileUrl(row[property].key)
+ if (typeof row[property] === "string") {
+ row[property] = JSON.parse(row[property])
+ }
+ if (Array.isArray(row[property])) {
+ row[property].forEach((attachment: RowAttachment) => {
+ process(attachment)
+ })
+ } else {
+ process(row[property])
}
}
} else if (