0

Upload File

by
Published 8 days ago

Upload a file from Windmill object storage to Salesforce as a ContentVersion (Salesforce Files), optionally linking it to a record.

Script salesforce Verified

The script

Submitted by hugo989 Bun
Verified 9 days ago
1
import * as wmill from "windmill-client"
2
import { S3Object } from "windmill-client"
3

4
/**
5
 * Upload File
6
 * Upload a file from Windmill object storage to Salesforce as a ContentVersion (Salesforce Files), optionally linking it to a record.
7
 */
8
export async function main(
9
  auth: RT.Salesforce,
10
  file: S3Object,
11
  title: string,
12
  linked_record_id: string | undefined
13
) {
14
  const apiVersion = auth.api_version || "v60.0"
15

16
  // Load the file bytes from Windmill's object storage and base64-encode for VersionData.
17
  const bytes = await wmill.loadS3File(file)
18
  if (!bytes) {
19
    throw new Error("Could not load the file from object storage")
20
  }
21
  const versionData = Buffer.from(bytes).toString("base64")
22

23
  // 1. Create the ContentVersion (the uploaded file).
24
  const cvResponse = await fetch(
25
    `${auth.instance_url}/services/data/${apiVersion}/sobjects/ContentVersion`,
26
    {
27
      method: "POST",
28
      headers: {
29
        Authorization: `Bearer ${auth.token}`,
30
        "Content-Type": "application/json",
31
        Accept: "application/json",
32
      },
33
      body: JSON.stringify({
34
        Title: title,
35
        PathOnClient: title,
36
        VersionData: versionData,
37
      }),
38
    }
39
  )
40
  if (!cvResponse.ok) {
41
    throw new Error(`${cvResponse.status} ${await cvResponse.text()}`)
42
  }
43
  const contentVersion = (await cvResponse.json()) as { id: string }
44

45
  if (linked_record_id === undefined || linked_record_id === "") {
46
    return contentVersion
47
  }
48

49
  // 2. Resolve the ContentDocumentId of the new version.
50
  const queryUrl = new URL(
51
    `${auth.instance_url}/services/data/${apiVersion}/query`
52
  )
53
  queryUrl.searchParams.append(
54
    "q",
55
    `SELECT ContentDocumentId FROM ContentVersion WHERE Id = '${contentVersion.id}'`
56
  )
57
  const queryResponse = await fetch(queryUrl, {
58
    headers: {
59
      Authorization: `Bearer ${auth.token}`,
60
      Accept: "application/json",
61
    },
62
  })
63
  if (!queryResponse.ok) {
64
    throw new Error(`${queryResponse.status} ${await queryResponse.text()}`)
65
  }
66
  const contentDocumentId = (
67
    (await queryResponse.json()) as {
68
      records: { ContentDocumentId: string }[]
69
    }
70
  ).records[0].ContentDocumentId
71

72
  // 3. Link the file to the target record.
73
  const linkResponse = await fetch(
74
    `${auth.instance_url}/services/data/${apiVersion}/sobjects/ContentDocumentLink`,
75
    {
76
      method: "POST",
77
      headers: {
78
        Authorization: `Bearer ${auth.token}`,
79
        "Content-Type": "application/json",
80
        Accept: "application/json",
81
      },
82
      body: JSON.stringify({
83
        ContentDocumentId: contentDocumentId,
84
        LinkedEntityId: linked_record_id,
85
        ShareType: "V",
86
      }),
87
    }
88
  )
89
  if (!linkResponse.ok) {
90
    throw new Error(`${linkResponse.status} ${await linkResponse.text()}`)
91
  }
92

93
  return {
94
    contentVersionId: contentVersion.id,
95
    contentDocumentId,
96
    linkedEntityId: linked_record_id,
97
    success: true,
98
  }
99
}
100