1 | |
2 |
|
3 | import * as wmill from "windmill-client" |
4 |
|
5 | const graph = "https://graph.microsoft.com/v1.0" |
6 |
|
7 | export type DynSelect_site_id = string |
8 |
|
9 | export async function site_id(auth: RT.MsSharepoint) { |
10 | const response = await fetch( |
11 | `${graph}/sites?search=*&$select=id,displayName,webUrl&$top=200`, |
12 | { |
13 | headers: { |
14 | Authorization: `Bearer ${auth.token}`, |
15 | Accept: "application/json", |
16 | }, |
17 | } |
18 | ) |
19 | if (!response.ok) { |
20 | throw new Error(`${response.status} ${await response.text()}`) |
21 | } |
22 | const { value } = (await response.json()) as { |
23 | value: { id: string; displayName: string; webUrl: string }[] |
24 | } |
25 | return value.map((s) => ({ |
26 | value: s.id, |
27 | label: `${s.displayName} (${s.webUrl})`, |
28 | })) |
29 | } |
30 |
|
31 | export type DynSelect_list_id = string |
32 |
|
33 | export async function list_id(auth: RT.MsSharepoint, site_id: string) { |
34 | const response = await fetch( |
35 | `${graph}/sites/${site_id}/lists?$select=id,displayName`, |
36 | { |
37 | headers: { |
38 | Authorization: `Bearer ${auth.token}`, |
39 | Accept: "application/json", |
40 | }, |
41 | } |
42 | ) |
43 | if (!response.ok) { |
44 | throw new Error(`${response.status} ${await response.text()}`) |
45 | } |
46 | const { value } = (await response.json()) as { |
47 | value: { id: string; displayName: string }[] |
48 | } |
49 | return value.map((l) => ({ value: l.id, label: l.displayName })) |
50 | } |
51 |
|
52 | |
53 | * New or Updated List Item |
54 | * Emits the items created (or, with `events`, also modified) in a list since the last poll, with their column values. The first run records the newest item and emits nothing. Polls because Microsoft Graph push needs a change-notification subscription renewed every few weeks against a public endpoint, which belongs in a Windmill native trigger; run this as a Scheduled Poll until then. Requires Sites.Read.All (covered by the default Sites.ReadWrite.All). |
55 | */ |
56 | export async function main( |
57 | auth: RT.MsSharepoint, |
58 | site_id: DynSelect_site_id, |
59 | list_id: DynSelect_list_id, |
60 | events: "created" | "created_or_updated" = "created" |
61 | ) { |
62 | const field = |
63 | events === "created" ? "createdDateTime" : "lastModifiedDateTime" |
64 | const since: number | undefined = await wmill.getState() |
65 |
|
66 | |
67 | |
68 | const items: { [key: string]: any }[] = [] |
69 | let next: string | undefined = |
70 | `${graph}/sites/${site_id}/lists/${list_id}/items?$expand=fields&$top=200` |
71 | while (next) { |
72 | const response = await fetch(next, { |
73 | headers: { |
74 | Authorization: `Bearer ${auth.token}`, |
75 | Accept: "application/json", |
76 | }, |
77 | }) |
78 | if (!response.ok) { |
79 | throw new Error(`${response.status} ${await response.text()}`) |
80 | } |
81 | const page = (await response.json()) as { |
82 | value: { [key: string]: any }[] |
83 | "@odata.nextLink"?: string |
84 | } |
85 | items.push(...page.value) |
86 | next = page["@odata.nextLink"] |
87 | } |
88 |
|
89 | |
90 | const newest = items.reduce( |
91 | (max, i) => Math.max(max, Date.parse(i[field])), |
92 | since ?? 0 |
93 | ) |
94 | await wmill.setState(newest) |
95 |
|
96 | |
97 | if (since == null) return [] |
98 |
|
99 | return items.filter((i) => Date.parse(i[field]) > since) |
100 | } |
101 |
|