0

Upload Attachment

by
Published Oct 31, 2023

Attach a file from Windmill object storage to a task, project or project brief (max 100 MB). The file keeps the name at the end of its storage path unless `name` is set.

Script asana Verified

The script

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

4
/**
5
 * Upload Attachment
6
 * Attach a file from Windmill object storage to a task, project or project brief (max 100 MB). The file keeps the name at the end of its storage path unless `name` is set.
7
 */
8
export async function main(
9
  auth: RT.Asana,
10
  parent: string,
11
  file: S3Object,
12
  name: string | undefined
13
) {
14
  const bytes = await wmill.loadS3File(file)
15
  if (!bytes) {
16
    throw new Error(`Could not load ${file.s3} from object storage`)
17
  }
18

19
  const form = new FormData()
20
  form.append("parent", parent)
21
  form.append("file", new Blob([bytes]), name || file.s3.split("/").pop())
22

23
  const response = await fetch("https://app.asana.com/api/1.0/attachments", {
24
    method: "POST",
25
    headers: {
26
      Authorization: `Bearer ${auth.token}`,
27
      Accept: "application/json",
28
    },
29
    body: form,
30
  })
31

32
  if (!response.ok) {
33
    throw new Error(`${response.status} ${await response.text()}`)
34
  }
35

36
  return await response.json()
37
}
38

Other submissions
  • Submitted by hugo697 Typescript (fetch-only)
    Created 528 days ago
    1
    type Asana = {
    2
      token: string;
    3
    };
    4
    type Base64 = string;
    5
    /**
    6
     * Upload an attachment
    7
     * Upload an attachment.
    8
     */
    9
    export async function main(
    10
      auth: Asana,
    11
      opt_pretty: string | undefined,
    12
      opt_fields: string | undefined,
    13
      body: {
    14
        connect_to_app?: boolean;
    15
        file?: {
    16
          base64: Base64;
    17
          type:
    18
            | "image/png"
    19
            | "image/jpeg"
    20
            | "image/gif"
    21
            | "application/pdf"
    22
            | "appication/json"
    23
            | "text/csv"
    24
            | "text/plain"
    25
            | "audio/mpeg"
    26
            | "audio/wav"
    27
            | "video/mp4";
    28
          name: string;
    29
        };
    30
        name?: string;
    31
        parent?: string;
    32
        resource_subtype?:
    33
          | "asana"
    34
          | "dropbox"
    35
          | "gdrive"
    36
          | "onedrive"
    37
          | "box"
    38
          | "vimeo"
    39
          | "external";
    40
        url?: string;
    41
        [k: string]: unknown;
    42
      }
    43
    ) {
    44
      const url = new URL(`https://app.asana.com/api/1.0/attachments`);
    45
      for (const [k, v] of [
    46
        ["opt_pretty", opt_pretty],
    47
        ["opt_fields", opt_fields],
    48
      ]) {
    49
        if (v !== undefined && v !== "") {
    50
          url.searchParams.append(k, v);
    51
        }
    52
      }
    53
      const formData = new FormData();
    54
      for (const [k, v] of Object.entries(body)) {
    55
        if (v !== undefined && v !== "") {
    56
          if (["file"].includes(k)) {
    57
            const { base64, type, name } = v as {
    58
              base64: Base64;
    59
              type: string;
    60
              name: string;
    61
            };
    62
            formData.append(
    63
              k,
    64
              new Blob([Uint8Array.from(atob(base64), (m) => m.codePointAt(0)!)], {
    65
                type,
    66
              }),
    67
              name
    68
            );
    69
          } else {
    70
            formData.append(k, String(v));
    71
          }
    72
        }
    73
      }
    74
      const response = await fetch(url, {
    75
        method: "POST",
    76
        headers: {
    77
          Authorization: "Bearer " + auth.token,
    78
        },
    79
        body: formData,
    80
      });
    81
      if (!response.ok) {
    82
        const text = await response.text();
    83
        throw new Error(`${response.status} ${text}`);
    84
      }
    85
      return await response.json();
    86
    }
    87