HarsHarI
HarsHarI

Reputation: 911

How to upload file into box.com

i am working on file upload into box.com but i am stuck there. i used Net::HTTP for that and i need the help of regarding this library.

my main code which interact to box.com is

module BoxApi
  class FileOperation < Base
    attr_reader :upload_path

    def initialize
      super
      @upload_path = "https://upload.box.com/api/2.0/files/content"
    end

#here filder_id args denote folder inside upload file and file args hold the content of file which are uploaded by file_field

    def upload(folder_id, file)
       boundary = "AaB03x"
       body = []
       body << "--#{boundary}\r\n"
       body << "Content-Disposition: form-data; name='filename'; filename=#{file.original_filename}\r\n"
       body << "Content-Type: text/plain\r\n\r\n"
       body << file
       body << "--#{boundary}\r\n"
       body << "Content-Disposition: form-data; name='parent_id'"
       body << "\r\n"
       body << folder_id
       body << "\r\n--#{boundary}--\r\n"

      https_post(URI.parse("#{upload_path}"), body, boundary)
      # `curl "Authorization: Bearer MlaNbyAefUWrawZEqGkDKvq9foCmQ0lL" -F filename=@./public/404.html -F parent_id='#{folder_id}' #{upload_path}`
    rescue => ex
      p "Exception caught (1) ==> #{ex}"
    end

    private
    def https_post(uri, body, boundary)
      http = https_setting(uri)
      request = Net::HTTP::Post.new(uri.request_uri)
      # request.body = JSON.parse(body)
      request.body = body.join
      request["Content-Type"] = "multipart/form-data, boundary=#{boundary}"
      request["Authorization"] = "Bearer #{box_token.token}"
      http.request(request)
    rescue => ex
      p "Exception caught (2) ==> #{ex}"
    end

    def https_setting(uri)
      http = Net::HTTP.new(uri.host, uri.port)
      http.use_ssl = true
      http.verify_mode = OpenSSL::SSL::VERIFY_NONE  
      http
    end
  end
end

Upvotes: 2

Views: 801

Answers (3)

Bryce Nordgren
Bryce Nordgren

Reputation: 3

Another translation of @NitrusCS into Python3 using the requests library. I was inspired by the bash code of @Kubuntuer82.

I'll include the gist here:

import datetime
import requests
import urllib
import os.path
import sys
import json

#
# Given a "File Request URL" and a local file, this program uploads to a box folder.
#
class BoxUploader(object) : 

  def __init__(self, requestURL) :
    self.request_url = requestURL
    o = urllib.parse.urlparse(requestURL) 
    
    self.boxDomain = o.hostname
    self.fileRequestId = os.path.basename(o.path)

    self.initialUrl = 'https://' + self.boxDomain + '/app-api/file-request-web/public/file-request?urlId=' + self.fileRequestId
    self.formResponseUrl = 'https://' + self.boxDomain + '/app-api/file-request-web/public/form-response'
    self.optionsUrl      = 'https://' + self.boxDomain + '/api/2.1/files/content'

  def upload_file(self, fname) : 
    #
    # Initial call to the "get" url
    #
    rfc3339_format='%Y-%m-%dT%H:%M:%S%z'
    response = requests.get(self.initialUrl)
    jsonResponse = response.json()
    basename = os.path.basename(fname)
    local_timezone= datetime.datetime.now(datetime.timezone.utc).astimezone().tzinfo
    modifiedTime = datetime.datetime.fromtimestamp(os.path.getmtime(fname), tz=local_timezone)

    #
    # Submit a form response to get an upload token
    #
    boxFileRequestId = jsonResponse['id']
    boxFolderId      = jsonResponse['folder']['id']
    formVersionId    = jsonResponse['form']['versionId']
    fileLength = os.path.getsize(fname)
    print("Form Version ID: " + formVersionId)
    requestContent = { "fileRequestURL" : self.fileRequestId,
                       "formVersionId"  : formVersionId,
                       "values"         : {"element-0" : { "type":"files", "data":[ {"local_path":fname, "size":fileLength}] },
                                           "folder"    : {"type" : "folder", "id": boxFolderId}}}
    uploadFormResponse = requests.post(self.formResponseUrl, json=requestContent)
    uploadFormResponseJson = uploadFormResponse.json()

    #
    # Make a call to the options url to get the actual url to
    # upload the file to.
    #
    uploadToken = uploadFormResponseJson['uploadToken']
    headers     = { "Authorization" : "Bearer " + uploadToken }
    requestContent = { "name" : fname,
                       "parent": { "id" : boxFolderId },
                       "size": fileLength}
    optionsResponse = requests.options(self.optionsUrl, headers=headers, json=requestContent)
    optionsResponseJson = optionsResponse.json() 


    # Upload the file.
    upload_url = optionsResponseJson['upload_url']
    form_attributes = { 'name' : fname, 
                        'parent': {"id": boxFolderId},
                        'content_modified_at' : modifiedTime.strftime(rfc3339_format) } 
    files={ 'attributes' : (None, json.dumps(form_attributes), 'application/json', {'Content-Disposition':'form-data'}), 
            'file'       : (fname, open(fname, 'rb')) }
    #upload_request = requests.Request('POST', upload_url, headers=headers, files=files).prepare()
    #print(upload_request.headers)
    #print(upload_request.body) 
    uploadResponse = requests.post(upload_url, headers=headers, files=files)
    print(json.dumps(uploadResponse.json(), indent=2))


def main(requestUrl, file) : 
  uploader = BoxUploader(requestUrl)
  uploader.upload_file(file)

if __name__ == '__main__' : 
  url = sys.argv[1]
  file = sys.argv[2]
  main(url, file)

Upvotes: 0

GeekInDisguise
GeekInDisguise

Reputation: 1567

This is a translation of the code by @NitrusCS into Bash. It took a while and it's not identical, but it works.

#!/bin/bash
        
#CONSTANTS

BoxDomain="yourenterprise.ent.box.com"
formVersionId="1576913797"

#FUNCTIONS

function getdate() {
date "+%A, %B %d, %Y %I:%M:%S %p" | sed 's/am$/AM/g' | sed 's/pm$/PM/g'
}

function datetimeinticks() {
printf '%x\n' $(echo $(($(($(date '+%s') - $(date -d "0001-01-01T00:00:00.0000000 +0200" '+%s'))) * 10000000 + $((10#$(date '+%N')/100)) )))
}

#ARGUMENTS

FileRequestID="$1"
FileToUpload="$2"
FileName=$(basename $FileToUpload)
FileLength=$(stat --printf="%s" "$FileToUpload")

#MAIN CODE

URL="https://$BoxDomain/app-api/file-request-web/public/file-request?urlId=$FileRequestID"

echo -n "[$FileName] Preparing for upload:   0%"

resultsRaw=$(curl -s -X GET "$URL")
echo "$resultsRaw" > ${FileName}_errors.log
echo -en "\r[$FileName] Preparing for upload:  33%"
boxFolderId=$(echo $resultsRaw | jq ".folder" | jq ".id")

ProcessStartDateTime=$(getdate)

requestContent="{\"fileRequestURL\": \"$FileRequestID\",\"formVersionId\": \"$formVersionId\",\"values\":{\"element-0\":{\"type\":\"files\",\"data\":[{\"local_path\":\"$FileName\",\"size\":$FileLength}]},\"folder\":{\"type\":\"folder\",\"id\":$boxFolderId}}}"

UploadFormResponse=$(curl -s "https://$BoxDomain/app-api/file-request-web/public/form-response" -X POST -H "content-type: application/json;charset=UTF-8" -d "$requestContent")
echo "$UploadFormResponse" >> ${FileName}_errors.log
echo -en "\r[$FileName] Preparing for upload:  67%"

uploadToken=$(echo $UploadFormResponse | jq ".uploadToken" | sed 's/^\"//g' | sed 's/\"$//g')

requestContent="{\"name\":\"$FileName\",\"parent\":{\"id\":$boxFolderId},\"size\":$FileLength}"
OptionsResponse=$(curl -s "https://$BoxDomain/api/2.1/files/content" -X OPTIONS -H "Authorization: Bearer $uploadToken" -d "$requestContent")
echo "$OptionsResponse" >> ${FileName}_errors.log
echo -e "\r[$FileName] Preparing for upload: 100% ... "

UploadURL=$(echo $OptionsResponse | jq ".upload_url" | sed 's/^\"//g' | sed 's/\"$//g')

boundary="---------------------------$(datetimeinticks)"
LastWriteTimeUtc=$(date -u -d "$(stat --printf=%y "$FileToUpload")" '+%Y-%m-%dT%H:%M:%SZ')

boundarystring="$(echo -en "\r\n--" ; echo -n $boundary ; echo -en "\r\n" ; echo .)"
boundarystring=${boundarystring%.}

rs="${FileName}_requestdata.http"
touch $rs

echo -n "$boundarystring" > $rs

formAttributes="$(echo -en "Content-Disposition: form-data; name=\"attributes\"\r\n\r\n{\"name\":\"$FileName\",\"parent\":{\"id\":$boxFolderId},\"content_modified_at\":\"$LastWriteTimeUtc\"}" ; echo .)"
formAttributes=${formAttributes%.}
echo -n "$formAttributes" >> $rs

echo -n "$boundarystring" >> $rs

formFile="$(echo -en "Content-Disposition: form-data; name=\"file\"; filename=\"$FileName\"\r\nContent-Type: application/octet-stream\r\n\r\n" ; echo .)"
formFile=${formFile%.}
echo -n "$formFile" >> $rs

echo -n "[$FileName] Preparing the file to upload..."
cat "$FileToUpload" >> $rs

trailerstring="$(echo -en "\r\n--" ; echo -n $boundary ; echo -en "--\r\n" ; echo .)"
trailerstring=${trailerstring%.}
echo -n "$trailerstring" >> $rs

echo "[$FileName] Uploading:"
response=$(curl -X POST -H "content-type: multipart/form-data; boundary=$boundary" -H "Authorization: Bearer $uploadToken" --data-binary @$rs "$UploadURL")
echo "$response" >> ${FileName}_errors.log
echo $response | grep -q '"type":"file"' && { echo "[$FileName] Upload complete" ; rm ${FileName}_errors.log ; rm $rs ; }
echo $response | grep -q '"type":"file"' || echo "[$FileName] Upload failed: See file ${FileName}_errors.log for details."

Upvotes: 0

NitrusCS
NitrusCS

Reputation: 753

Here's my Powershell code which uses System.Net.HttpWebRequest

param(
    $FileRequestID ,
    $FileToUpload 
)

$BoxDomain = "yourenterprise.ent.box.com"

$URL = "https://$($BoxDomain)/app-api/file-request-web/public/file-request?urlId=$($FileRequestID)"

$resultsRaw = Invoke-WebRequest -Uri $URL -Method GET -UseBasicParsing

$resultsJson = ConvertFrom-Json $resultsRaw.Content
$boxFileRequestId = $resultsJson.id
$boxFolderId = $resultsJson.folder.id

$fileInfo = [System.IO.FileInfo]$FileToUpload
$ProcessStartDateTime = Get-Date
$ProgressName = "$($fileInfo.Name) Upload Progress"

$requestContent = "{`"fileRequestURL`":`"$($FileRequestID)`",`"formVersionId`":`"303881722`",`"values`":{`"element-0`":{`"type`":`"files`",`"data`":[{`"local_path`":`"$($fileInfo.Name)`",`"size`":$($fileInfo.Length)}]},`"folder`":{`"type`":`"folder`",`"id`":`"$($boxFolderId)`"}}}"
$UploadFormResponse = Invoke-WebRequest -Uri "https://$($BoxDomain)/app-api/file-request-web/public/form-response" -Method POST -ContentType "application/json;charset=UTF-8" -Body $requestContent -UseBasicParsing

$UploadFormResponseJson = ConvertFrom-Json $UploadFormResponse.Content

$requestContent = "{`"name`":`"$($fileInfo.Name)`",`"parent`":{`"id`":`"$($boxFolderId)`"},`"size`":$($fileInfo.Length)}" 
$OptionsResponse = Invoke-WebRequest -Uri "https://$($BoxDomain)/api/2.1/files/content" -Method OPTIONS -Body $requestContent -Headers @{ Authorization = "Bearer $($UploadFormResponseJson.uploadToken)";} -UseBasicParsing

$OptionsResponseJson = ConvertFrom-Json $OptionsResponse.Content

$UploadURL = $OptionsResponseJson.upload_url

$boundary = "---------------------------" +[System.DateTime]::Now.Ticks.ToString("x");
$boundarybytes = [System.Text.Encoding]::ASCII.GetBytes("`r`n--" + $boundary + "`r`n");
$wr = [System.Net.HttpWebRequest]([System.Net.WebRequest]::Create($UploadURL));
$wr.ContentType = "multipart/form-data; boundary=" + $boundary;
$wr.Method = "POST";
$wr.KeepAlive = $true;
$wr.PreAuthenticate = $true
$wr.Headers.Add("Authorization", "Bearer $($UploadFormResponseJson.uploadToken)")
$wr.AllowWriteStreamBuffering = $false
$wr.SendChunked = $true
$rs = $wr.GetRequestStream();

#Write attributes
$rs.Write($boundarybytes, 0, $boundarybytes.Length);
$formAttributes = "Content-Disposition: form-data; name=`"attributes`"`r`n`r`n{`"name`":`"$($fileInfo.Name)`",`"parent`":{`"id`":`"$($boxFolderId)`"},`"content_modified_at`":`"$($fileInfo.LastWriteTimeUtc.ToString("yyyy-MM-ddTHH:mm:ssZ"))`"}"

$formAttributesBytes = [System.Text.Encoding]::UTF8.GetBytes($formAttributes)
$rs.Write($formAttributesBytes, 0, $formAttributesBytes.Length)

#Write File
$rs.Write($boundarybytes, 0, $boundarybytes.Length);
$formFile = "Content-Disposition: form-data; name=`"file`"; filename=`"$($fileInfo.Name)`"`r`nContent-Type: application/octet-stream`r`n`r`n"
$formFileBytes = [System.Text.Encoding]::UTF8.GetBytes($formFile)
$rs.Write($formFileBytes, 0, $formFileBytes.Length)

[System.IO.FileStream]$fileStream = [System.IO.File]::Open($fileInfo.FullName, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::ReadWrite)
$buffer = [System.Byte[]]::new(1048576)
$bytesRead = 0;
$totalBytesRead = 0
$totalBytesToRead = $fileInfo.Length
while (($bytesRead = $fileStream.Read($buffer, 0, $buffer.Length)) -ne 0) {
    $rs.Write($buffer, 0, $bytesRead);
    $rs.Flush()
    $totalBytesRead += $bytesRead
    $SecondsElapsed = ((Get-Date) - $ProcessStartDateTime).TotalSeconds
    $SecondsRemaining = ($SecondsElapsed / ($totalBytesRead / $totalBytesToRead)) - $SecondsElapsed
    Write-Progress -Activity $ProgressName -PercentComplete (($totalBytesRead/$($totalBytesToRead)) * 100) -CurrentOperation "$("{0:N2}" -f ((($totalBytesRead/$($totalBytesToRead)) * 100),2))% Complete" -SecondsRemaining $SecondsRemaining
}
$fileStream.Close();
$trailerBytes = [System.Text.Encoding]::ASCII.GetBytes("`r`n--" + $boundary + "`r`n");
$rs.Write($trailerBytes, 0, $trailerBytes.Length);
$rs.Close();

#Done writing File

$wresp = $wr.GetResponse();
$wresp.StatusCode
$stream2 = $wresp.GetResponseStream();
$reader2 = New-Object -TypeName System.IO.StreamReader -ArgumentList $stream2
$response = ConvertFrom-Json ($reader2.ReadToEnd())
#$response

Upvotes: 1

Related Questions