0

Upload File

by
Published today

Upload a file from Windmill object storage to Slack, optionally sharing it to a channel or thread.

Script slack Verified

The script

Submitted by hugo989 Bun
Verified 1 hour ago
1
import { WebClient } from "@slack/web-api"
2
import * as wmill from "windmill-client"
3
import { S3Object } from "windmill-client"
4

5
export type DynSelect_channel = string
6

7
// Dropdown of channels the token can see; private channels need groups:read.
8
export async function channel(auth: RT.Slack) {
9
  if (!auth?.token) return []
10
  const client = new WebClient(auth.token)
11
  const res = await client.conversations
12
    .list({
13
      types: "public_channel,private_channel",
14
      exclude_archived: true,
15
      limit: 1000,
16
    })
17
    .catch(() =>
18
      client.conversations.list({ exclude_archived: true, limit: 1000 })
19
    )
20
  return (res.channels ?? []).map((c) => ({
21
    value: c.id!,
22
    label: `#${c.name}`,
23
  }))
24
}
25

26
/**
27
 * Upload File
28
 * Upload any file from Windmill object storage. With `channel` it is shared there (with an optional `initial_comment`, or as a thread reply with `thread_ts`); without it the file stays private to the uploader. Uses files.getUploadURLExternal + files.completeUploadExternal. Needs files:write (bot default; tick it for a user token); a bot must be in the channel.
29
 */
30
export async function main(
31
  auth: RT.Slack,
32
  file: S3Object,
33
  filename: string,
34
  channel?: DynSelect_channel,
35
  title?: string,
36
  initial_comment?: string,
37
  thread_ts?: string
38
) {
39
  const bytes = await wmill.loadS3File(file)
40
  if (!bytes) {
41
    throw new Error("Could not load the file from object storage")
42
  }
43

44
  const client = new WebClient(auth.token)
45
  return await client.filesUploadV2(
46
    dropEmpty({
47
      file: Buffer.from(bytes),
48
      filename,
49
      channel_id: channel,
50
      title,
51
      initial_comment,
52
      thread_ts,
53
    }) as any
54
  )
55
}
56

57
function dropEmpty<T extends { [key: string]: any }>(params: T) {
58
  return Object.fromEntries(
59
    Object.entries(params).filter(
60
      ([, v]) => v !== undefined && v !== null && v !== ""
61
    )
62
  ) as T
63
}
64