//native
import * as wmill from "windmill-client"
const graph = "https://graph.microsoft.com/v1.0"
export type DynSelect_site_id = string
export async function site_id(auth: RT.MsSharepoint) {
const response = await fetch(
`${graph}/sites?search=*&$select=id,displayName,webUrl&$top=200`,
{
headers: {
Authorization: `Bearer ${auth.token}`,
Accept: "application/json",
},
}
)
if (!response.ok) {
throw new Error(`${response.status} ${await response.text()}`)
}
const { value } = (await response.json()) as {
value: { id: string; displayName: string; webUrl: string }[]
}
return value.map((s) => ({
value: s.id,
label: `${s.displayName} (${s.webUrl})`,
}))
}
export type DynSelect_list_id = string
export async function list_id(auth: RT.MsSharepoint, site_id: string) {
const response = await fetch(
`${graph}/sites/${site_id}/lists?$select=id,displayName`,
{
headers: {
Authorization: `Bearer ${auth.token}`,
Accept: "application/json",
},
}
)
if (!response.ok) {
throw new Error(`${response.status} ${await response.text()}`)
}
const { value } = (await response.json()) as {
value: { id: string; displayName: string }[]
}
return value.map((l) => ({ value: l.id, label: l.displayName }))
}
/**
* New or Updated List Item
* 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).
*/
export async function main(
auth: RT.MsSharepoint,
site_id: DynSelect_site_id,
list_id: DynSelect_list_id,
events: "created" | "created_or_updated" = "created"
) {
const field =
events === "created" ? "createdDateTime" : "lastModifiedDateTime"
const since: number | undefined = await wmill.getState()
// ponytail: reads the whole list every poll, as the timestamps cannot be
// filtered server-side without an indexed column; switch to items/delta if lists get large
const items: { [key: string]: any }[] = []
let next: string | undefined =
`${graph}/sites/${site_id}/lists/${list_id}/items?$expand=fields&$top=200`
while (next) {
const response = await fetch(next, {
headers: {
Authorization: `Bearer ${auth.token}`,
Accept: "application/json",
},
})
if (!response.ok) {
throw new Error(`${response.status} ${await response.text()}`)
}
const page = (await response.json()) as {
value: { [key: string]: any }[]
"@odata.nextLink"?: string
}
items.push(...page.value)
next = page["@odata.nextLink"]
}
// The watermark is the newest timestamp seen, so it follows SharePoint's clock
const newest = items.reduce(
(max, i) => Math.max(max, Date.parse(i[field])),
since ?? 0
)
await wmill.setState(newest)
// First run: set the watermark and don't emit a backlog
if (since == null) return []
return items.filter((i) => Date.parse(i[field]) > since)
}
Submitted by hugo989 5 hours ago