Caricare un'immagine locale utilizzando l'API

Ciao a tutti,

spero che questo sia il posto giusto per chiedere. Sto lavorando all’importazione di un insieme di dati da un altro forum nella nostra nuova istanza di Discourse (post sulla conoscenza interna che vogliamo migrare).
Ho i nostri vecchi dati ben impacchettati in diverse strutture JSON, ma mi sto bloccando sul caricamento delle varie immagini associate ai vecchi post.

Sto utilizzando il gem discourse_api e finora ho avuto un ottimo successo, anche se so che è incompleto. Posso caricare un’immagine con successo se quest’ultima è ospitata altrove, come in questo caso:

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

ma vado in stallo quando provo a caricare un’immagine che si trova sul mio computer locale:

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

…il risultato è il seguente errore:

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'

Ho dato un’occhiata intorno e ho capito che probabilmente devo fare qualche magia con il base64 o qualcosa di simile affinché la mia richiesta sia correttamente formata (sto anche realizzando che forse il metodo di caricamento del gem Ruby non può gestire questo tipo di upload, e in tal caso non c’è problema).

Principalmente sto cercando una guida, per vedere se qualcun altro si è imbattuto in questo problema e per capire se sto seguendo la strada sbagliata. Grazie in anticipo e buona giornata :slight_smile:

A meno che non ci sia un motivo per cui non puoi, ti consiglio di guardare nella directory dello script di importazione per vedere gli importatori che utilizzano file JSON. Sarà più semplice rispetto all’API.

Ciao Tony,

Sono d’accordo, caricare file locali può essere un po’ complicato da gestire tramite l’API. Ecco cosa dovrebbe funzionare:

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

client = DiscourseApi::Client.new("URL del sito Discourse")
client.api_key = "La tua chiave API"
client.api_username = "Nome utente"

filename = ARGV[1] # Percorso completo del 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 è l'ID del topic in cui vuoi caricare l'immagine.
args = {
  :topic_id => ARGV[0],
  :raw => "<img src=\"#{url}\" width=\"#{width}\" height=\"#{height}\">"
}

# Questo creerà un nuovo post nel topic specificato
resp = client.create_post(args)

Questo script utilizza il gem Faraday per fornire i requisiti corretti del file per upload_file. Una volta caricato il file, deve essere assegnato a un topic/post per essere visualizzato, altrimenti verrà eliminato automaticamente.

Puoi eseguire questo script con

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

Blake,

Grazie mille. Andrò a leggere qualcosa sul gem Faraday per capire cosa fa per me e proverò il tuo script. Apprezzo davvero molto il tempo che hai dedicato!

-tony.

Ho dedicato un bel po’ di tempo a capire come invocare l’endpoint di caricamento da uno script Python. Ho inizialmente seguito il consiglio di analizzare la chiamata API di caricamento tramite gli strumenti per sviluppatori di Chrome. Successivamente ho replicato la chiamata di caricamento tramite Postman. La parte che mi ha richiesto più tempo è stata tradurla in un codice Python funzionante. Per qualche motivo, il codice Python generato da Postman non funzionava nemmeno. Ecco come ha funzionato finalmente per me:

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