0

Download File

by
Published today

Download a file in a site's default document library, or in another of its libraries when `drive_id` is set to Windmill object storage and return its S3 reference. `item` is an id, or a path from the drive root starting with "/" (e.g. `/Reports/2026/summary.xlsx`). `convert_to_pdf` converts Office documents (docx, xlsx, pptx and others) to PDF on the way out. Requires Sites.Read.All (covered by the default Sites.ReadWrite.All).

Script ms_sharepoint Verified

The script

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

4
const graph = "https://graph.microsoft.com/v1.0"
5

6
export type DynSelect_site_id = string
7

8
export async function site_id(auth: RT.MsSharepoint) {
9
  const response = await fetch(
10
    `${graph}/sites?search=*&$select=id,displayName,webUrl&$top=200`,
11
    {
12
      headers: {
13
        Authorization: `Bearer ${auth.token}`,
14
        Accept: "application/json",
15
      },
16
    }
17
  )
18
  if (!response.ok) {
19
    throw new Error(`${response.status} ${await response.text()}`)
20
  }
21
  const { value } = (await response.json()) as {
22
    value: { id: string; displayName: string; webUrl: string }[]
23
  }
24
  return value.map((s) => ({
25
    value: s.id,
26
    label: `${s.displayName} (${s.webUrl})`,
27
  }))
28
}
29

30
export type DynSelect_drive_id = string
31

32
export async function drive_id(auth: RT.MsSharepoint, site_id: string) {
33
  const response = await fetch(
34
    `${graph}/sites/${site_id}/drives?$select=id,name`,
35
    {
36
      headers: {
37
        Authorization: `Bearer ${auth.token}`,
38
        Accept: "application/json",
39
      },
40
    }
41
  )
42
  if (!response.ok) {
43
    throw new Error(`${response.status} ${await response.text()}`)
44
  }
45
  const { value } = (await response.json()) as {
46
    value: { id: string; name: string }[]
47
  }
48
  return value.map((d) => ({ value: d.id, label: d.name }))
49
}
50

51
// The site's default document library, or the library given by drive_id
52
function driveUrl(site_id: string, drive_id: string | undefined) {
53
  return drive_id != null && drive_id !== ""
54
    ? `${graph}/drives/${encodeURIComponent(drive_id)}`
55
    : `${graph}/sites/${site_id}/drive`
56
}
57

58
// An item is addressed by its id, or by a path from the drive root starting with "/"
59
function ref(item: string | undefined) {
60
  if (item == null || item === "" || item === "/") return "root"
61
  if (!item.startsWith("/")) return `items/${encodeURIComponent(item)}`
62
  const path = item
63
    .replace(/\/+$/, "")
64
    .split("/")
65
    .map(encodeURIComponent)
66
    .join("/")
67
  return `root:${path}:`
68
}
69

70
/**
71
 * Download File
72
 * Download a file in a site's default document library, or in another of its libraries when `drive_id` is set to Windmill object storage and return its S3 reference. `item` is an id, or a path from the drive root starting with "/" (e.g. `/Reports/2026/summary.xlsx`). `convert_to_pdf` converts Office documents (docx, xlsx, pptx and others) to PDF on the way out. Requires Sites.Read.All (covered by the default Sites.ReadWrite.All).
73
 */
74
export async function main(
75
  auth: RT.MsSharepoint,
76
  site_id: DynSelect_site_id,
77
  item: string,
78
  destination: S3Object,
79
  convert_to_pdf: boolean = false,
80
  drive_id: DynSelect_drive_id | undefined
81
) {
82
  const drive = driveUrl(site_id, drive_id)
83
  const url = new URL(`${drive}/${ref(item)}/content`)
84
  if (convert_to_pdf) url.searchParams.append("format", "pdf")
85

86
  // Graph answers 302 to a pre-authenticated download URL, which fetch follows
87
  const response = await fetch(url, {
88
    headers: { Authorization: `Bearer ${auth.token}` },
89
  })
90

91
  if (!response.ok) {
92
    throw new Error(`${response.status} ${await response.text()}`)
93
  }
94

95
  await wmill.writeS3File(
96
    destination,
97
    response.body as ReadableStream<Uint8Array>
98
  )
99
  return destination
100
}
101