Загрузка локального изображения через API

Привет, друзья,

Надеюсь, я обращаюсь по адресу. Я работаю над импортом набора данных с другого форума в наш новый экземпляр Discourse (это внутренние посты с знаниями, которые мы хотим перенести).
У меня старые данные аккуратно упакованы в несколько структур JSON, но я застрял на загрузке различных изображений, связанных со старыми постами.

Я использую gem discourse_api и добился отличных успехов, хотя понимаю, что он не полон. Я могу успешно загрузить изображение, если оно размещено где-то в сети, например:

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

но я не могу загрузить изображение, которое находится на моём локальном компьютере:

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

…вышеуказанный запрос возвращает ошибку:

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'

Я достаточно покопался, чтобы понять, что, вероятно, мне нужно сделать какую-то магию с base64 или что-то в этом роде, чтобы мой запрос был правильно сформирован (я также понимаю, что, возможно, метод загрузки в ruby-геме просто не поддерживает такой тип загрузки (и если так, то это нормально).

В основном я просто ищу совета, чтобы узнать, сталкивался ли кто-то ещё с этой проблемой, и не иду ли я вовсе не в ту сторону. Заранее спасибо и всё такое :slight_smile:

Если у вас нет причин, по которым вы не можете этого сделать, рекомендую посмотреть в каталоге скриптов импорта на импортеры, использующие JSON-файлы. Это будет проще, чем работать с API.

Привет, Тони,

Согласен, загрузка локальных файлов через API может быть немного сложной. Вот что должно помочь:

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

client = DiscourseApi::Client.new("URL сайта Discourse")
client.api_key = "Ваш ключ API"
client.api_username = "Имя пользователя"

filename = ARGV[1] # Полный путь к файлу /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 — это идентификатор темы, в которую вы хотите загрузить изображение.
args = {
  :topic_id => ARGV[0],
  :raw => "<img src=\"#{url}\" width=\"#{width}\" height=\"#{height}\">"
}

# Это создаст новый пост в указанной теме
resp = client.create_post(args)

Этот скрипт использует gem Faraday для обеспечения правильных требований к файлу при вызове upload_file. После загрузки файла его необходимо привязать к теме или посту, иначе он будет автоматически удалён.

Вы можете запустить этот скрипт так:

ruby upload_image.rb <topic_id> <filename>
ruby upload_image.rb 128 /home/tony/mypic.png

Блейк,

Огромное спасибо. Я займусь изучением Faraday gem, чтобы понять, что именно он делает для меня, и протестирую твой скрипт. Я очень ценю, что ты уделил этому время!

-Тони.

Я потратил довольно много времени, пытаясь разобраться, как вызвать конечную точку загрузки из скрипта на Python. Сначала я последовал рекомендации и проанализировал вызов API загрузки через инструменты разработчика в Chrome. Затем я повторил этот вызов через Postman. Самым трудоёмким для меня было перевести это в рабочий код на Python. По какой-то причине сгенерированный Postman код на Python тоже не работал. Вот как у меня в итоге получилось:

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