API を使用したローカル画像のアップロード

Hey folks,

I hope this is the right place to ask. I’m working on importing a set of data from another forum into our new Discourse instance (internal knowledge posts that we want to transition).
I’ve got our old data nicely packed up in a bunch of JSON structures, but I’m getting hung up on uploading the various images that are related to the old posts.

I’m using the discourse_api gem and have had terrific success so far, though I realize that it’s incomplete. I can upload an image successfully if that image is hosted somewhere, like so:

client.upload_file({'user_id':24,url:'http://valid.url.here/foo.jpg','synchronous':true})

but I’m stymied when trying to upload an image that’s located on my local machine:

client.upload_file({'user_id':24,file:'/local/path/to/image/foo.jpg','synchronous':true})

…the above comes back with:

DiscourseApi::UnprocessableEntity: {"failed"=>"FAILED", 
"message"=>"undefined method 'tempfile' for 
#<String:0x00007f409d2fa398>"} from /home/user/.rvm/gems/
ruby-2.3.7/gems/discourse_api-0.36.0/lib/discourse_api/
client.rb:154:in 'handle_error'

I’ve poked around enough to realize that I probably need to do some base64 magic or something so that my request is properly formed (I’m also realizing that maybe the upload method for the ruby gem just can’t accommodate this type of upload (and if so, that’s fine).

Mostly I’m just looking for guidance, to see if anyone else has come up against this and to see if I’m barking up the wrong tree entirely. Thanks in advance, and all that :slight_smile:

「いいね!」 3

Unless there is some reason you cannot, I recommend looking at the import script directory to see importers that use json files. It’ll be easier than the API.

「いいね!」 2

Hi Tony,

I agree uploading local files can be a bit tricky to figure out using the API. This should do the trick:

# upload_image.rb
require 'discourse_api'
require 'fileutils'

client = DiscourseApi::Client.new("Discourse Site URL")
client.api_key = "Your api key"
client.api_username = "Username"

filename = ARGV[1] #full path to file /home/tony/mypic.png

args = {
  :file => Faraday::UploadIO.new(filename, 'image/png')
}

resp = client.upload_file(args)

url = resp['url']
width = resp['width']
height = resp['height']



# topic_id is the the id for the topic you want to upload the image to.
args = {
  :topic_id => ARGV[0],
  :raw => "<img src=\"#{url}\" width=\"#{width}\" height=\"#{height}\">"
}

# This will create a new post in the specified topic
resp = client.create_post(args)

This will use the Faraday gem to provide the correct file requirements for upload_file. Once the file is uploaded, it then needs to be assigned to a topic/post to show up or it will be auto deleted.

You can call this script with

ruby upload_image.rb <topic_id> <filename>
ruby upload_image.rb 128 /home/tony/mypic.png
「いいね!」 3

Blake,

Thanks a million. I’m going to go read up on the Faraday gem so that I know what it’s doing for me, and test out your script. I really appreciate you taking the time!

-tony.

「いいね!」 2

アップロードエンドポイントを Python スクリプトから呼び出す方法を理解するために、かなりの時間を費やしました。まず、Chrome 開発者ツールを使ってアップロード API 呼び出しをリバースエンジニアリングするという推奨に従いました。次に、Postman を通じてそのアップロード呼び出しを再現しました。私にとって時間を要したのは、それを動作する Python コードに変換する部分でした。何らかの理由で、Postman が生成した Python コードも動作しませんでした。以下が、私にとって最終的に動作した方法です:

requests.post('/uploads.json', files={'files[]': open('/path/to/image.png', 'rb')}, data={'type': 'composer'})

「いいね!」 3