Captain-Robot
Captain-Robot

Reputation: 123

Slack files.completeUploadExternal no uploading files to the Slack

Since the slack file.upload is going to be depreciated, I was going to make new the methods work.

The first one works as:

curl -s -F [email protected] -F filename=test.txt -F token=xoxp-token -F length=50123 https://slack.com/api/files.getUploadURLExternal

and returns

{"ok":true,"upload_url":"https:\/\/files.slack.com\/upload\/v1\/CwABAAAAXAoAAVnX....","file_id":"F07XXQ9XXXX"}

The second request is:

curl -X POST \  -H "Authorization: Bearer xoxp-token" \
  -H "Content-Type: application/json" \
  -d '{
        "files": [{"id":"F07XXXXXX", "title":"Slack API updates Testing"}],
        "channel_id": "C06EXXXXX"
      }' \
  https://slack.com/api/files.completeUploadExternal

With the second request, I get 200 OK responses.

{"ok":true,"files":[{"id":"XXXXXXX","created":XXXXXXXX,"timestamp":XXXXXXXX,"name":"test.txt","title":"Slack API updates Testing","mimetype":"","filetype":"","pretty_type":"","user":"XXXXXXXXX","user_team":"XXXXXXXXX","editable":false,"size":50123,"mode":"hosted","is_external":false,"external_type":"","is_public":false,"public_url_shared":false,"display_as_bot":false,"username":"","url_private":"https:\/\/files.slack.com\/files-pri\/XXXXXXXXX-XXXXXXX\/test.txt","url_private_download":"https:\/\/files.slack.com\/files-pri\/XXXXXXXXX-XXXXXXX\/download\/test.txt","media_display_type":"unknown","permalink":"https:\/\/XXXXXXXX.slack.com\/files\/XXXXXXXXX\/XXXXXXX\/test.txt","permalink_public":"https:\/\/slack-files.com\/XXXXXXXXX-XXXXXXX-XXXXXXXX","comments_count":0,"is_starred":false,"shares":{},"channels":[],"groups":[],"ims":[],"has_more_shares":false,"has_rich_preview":false,"file_access":"visible"}],"warning":"missing_charset","response_metadata":{"warnings":["missing_charset"]}}

Questions and problems: 1- How do I determine the length= in the first request (files.getUploadURLExternal ) 2- Even though I have provided the channel_id the file is still not getting uploaded on the Slack channel.

Documentation: https://api.slack.com/methods/files.completeUploadExternal https://api.slack.com/methods/files.getUploadURLExternal

Upvotes: 5

Views: 4346

Answers (5)

Akin Ozen
Akin Ozen

Reputation: 11

I believe slack's official documentation is wrong. El David's answer is working for me, slack suggests using PUT but it doesn't work. Using POST is solved it basically.

Upvotes: 0

JellyBeans
JellyBeans

Reputation: 41

Python implementation below, assuming a filestream input. I was getting the 'internal error: put' as well during the 2nd step, ended up being a malformed request

from io import BytesIO
import requests


SLACK_TOKEN = 'xxxxxxxxx'
SLACK_ENDPOINT = "https://slack.com/api/"


file_stream = BytesIO()
file_stream.write("Test text.".encode('utf-8'))
filename = 'arg.txt'


file_stream.seek(0, 2)  # Move to end of file
length = file_stream.tell()
file_stream.seek(0)  # Reset to start of file


# Get an upload URL
upload_url_resp = requests.post(
    url=f"{SLACK_ENDPOINT}files.getUploadURLExternal",
    headers={"Authorization": f"Bearer {SLACK_TOKEN}"},
    data={"filename": filename, "length": length}
)
upload_url_data = upload_url_resp.json()
if (upload_url := upload_url_data.get('upload_url')) and (file_id := upload_url_data.get('file_id')):
    # Upload the file to the returned URL
    up_resp = requests.post(
        upload_url,
        files={'file': (filename, file_stream)},
        json={'filename': filename}
    )
  
    resp = requests.post(
        url=f"{SLACK_ENDPOINT}files.completeUploadExternal",
        headers={"Authorization": f"Bearer {SLACK_TOKEN}"},
        json={
            "files": [{'id': file_id, 'title': filename}],
            "channel_id": 'tgt_channel_id',
            "initial_comment": "Testing File Upload",
        }
    )

Upvotes: 1

El David
El David

Reputation: 696

This is the complete bash script to upload any file using the slack API. Stage 4 is optional, only for personal token.

#!/bin/bash

export FILE_PATH="/folder/your.file"
export CHANNEL_ID="C_some_number"
export TOKEN="your_token"
FILENAME=$(basename "$FILE_PATH")

# Get the file size using macOS compatible stat command. use stat -c%s "$FILE_PATH" otherwise
FILE_SIZE=$(stat -f%z "$FILE_PATH")

# Stage 1: Get an upload URL
UPLOAD_URL_RESPONSE=$(curl -s -F files=@"$FILENAME" -F filename="$FILENAME" -F token=$TOKEN -F length=$FILE_SIZE https://slack.com/api/files.getUploadURLExternal)

UPLOAD_URL=$(echo "$UPLOAD_URL_RESPONSE" | jq -r '.upload_url')
FILE_ID=$(echo "$UPLOAD_URL_RESPONSE" | jq -r '.file_id')

if [ "$UPLOAD_URL" == "null" ]; then
  echo "Error getting upload URL: $UPLOAD_URL_RESPONSE"
  exit 1
fi

# Stage 2: Upload the file to the provided URL
UPLOAD_RESPONSE=$(curl -s -X POST \
  -T "$FILE_PATH" \
  -H "Content-Type: application/octet-stream" \
  "$UPLOAD_URL")

if [ $? -ne 0 ]; then
  echo "Error uploading file: $UPLOAD_RESPONSE"
  exit 1
fi

# Stage 3: Complete the upload, and post the message and the file
COMPLETE_RESPONSE=$(curl -s -X POST \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json;charset=utf-8" \
  -d '{
        "files": [
          {
            "id": "'"$FILE_ID"'"
          }
        ],
        "channel_id": "'"$CHANNEL_ID"'",
        "initial_comment": "Hello file 001"
      }' \
  https://slack.com/api/files.completeUploadExternal)

if [ "$(echo "$COMPLETE_RESPONSE" | jq -r '.ok')" != "true" ]; then
  echo "Error completing upload: $COMPLETE_RESPONSE"
  exit 1
fi

# OPTIONAL Stage 4: Share the uploaded file in a channel, only if it was not performed in the previous stage
SHARE_RESPONSE=$(curl -s -X POST \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json;charset=utf-8" \
  -d '{
        "channel": "'"$CHANNEL_ID"'",
        "file": "'"$FILE_ID"'",
        "initial_comment": "Hello file 002"
      }' \
  https://slack.com/api/files.sharedPublicURL)

if [ "$(echo "$SHARE_RESPONSE" | jq -r '.ok')" != "true" ]; then
  echo "Error sharing file: $SHARE_RESPONSE"
  exit 1
fi

echo "File successfully uploaded. Is not then check your token scopes"

Upvotes: 7

user25233734
user25233734

Reputation: 11

Im doing the same with my bot but in the step 2 when you have to upload the file, im getting an error "internal error: put".

upload_file = HTTP::Client.post(upload_url, headers, body: file_basename) //tried using file_basename and file_path

This is the answer to upload_file

#<HTTP::Client::Response:0x7f923f16caf0 @version="HTTP/1.1", @status=INTERNAL_SERVER_ERROR, @status_message="Internal Server Error", @headers=HTTP::Headers{"Content-Type" => "text/plain", "Content-Length" => "19", "Connection" => "close", "x-backend" => "miata-prod-gru-v2-5bcfb8465b-pt2fj", "date" => "Wed, 29 May 2024 19:06:28 GMT", "x-envoy-upstream-service-time" => "2", "x-edge-backend" => "miata", "x-slack-edge-shared-secret-outcome" => "shared-secret", "server" => "envoy", "via" => "envoy-edge-gru-cseuczvq, 1.1 5ea4a2b9e3595a42471d782e7c7054d0.cloudfront.net (CloudFront)", "X-Cache" => "Error from cloudfront", "X-Amz-Cf-Pop" => "EZE50-P1", "X-Amz-Cf-Id" => "LfAqYrT_5Pc-XdooQfTjR9U2cH4uxabEx-5Yki8r5qVKPSRVY-2UQw==", "Cross-Origin-Resource-Policy" => "cross-origin"}, @body_io=nil, @cookies=nil, @body="internal error: put">

Upvotes: 1

user3591490
user3591490

Reputation: 16

You skipped a step. You have to send a POST to the URL that is returned to you on the first step. In that post you are also doing the file upload.

2nd step should be: curl -F filename="@$filename" -H "Authorization: Bearer $SLACK_KEY" -v POST $upload_url

then your 2nd step should be the 3rd step.

As far as getting the byte size stat --printf="%s" file if you are using bash

Upvotes: 0

Related Questions