Lokales Bild mit der API hochladen

Hey Leute,

ich hoffe, das ist der richtige Ort, um zu fragen. Ich arbeite daran, eine Reihe von Daten aus einem anderen Forum in unsere neue Discourse-Instanz zu importieren (interne Wissensbeiträge, die wir migrieren möchten).
Ich habe unsere alten Daten schön in einer Reihe von JSON-Strukturen verpackt, aber ich stecke beim Hochladen der verschiedenen Bilder fest, die mit den alten Beiträgen verknüpft sind.

Ich verwende das discourse_api-Gem und hatte bisher hervorragende Erfolge, obwohl mir bewusst ist, dass es unvollständig ist. Ich kann ein Bild erfolgreich hochladen, wenn dieses Bild irgendwo gehostet ist, wie folgt:

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

aber ich scheitere, wenn ich versuche, ein Bild hochzuladen, das sich auf meinem lokalen Rechner befindet:

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

…das oben genannte führt zu folgendem Fehler:

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'

Ich habe mich ausreichend umgeschaut und festgestellt, dass ich wahrscheinlich etwas Base64-Magie oder Ähnliches anwenden muss, damit meine Anfrage korrekt formatiert ist (ich erkenne auch, dass die Upload-Methode des Ruby-Gems diesen Upload-Typ vielleicht gar nicht unterstützen kann – und wenn das so ist, ist das auch in Ordnung).

Eigentlich suche ich nur nach einer Anleitung, um zu sehen, ob andere bereits auf dieses Problem gestoßen sind und ob ich vielleicht am falschen Ende der Leine ziehe. Vielen Dank im Voraus und alles Gute :slight_smile:

Sofern nichts dagegen spricht, empfehle ich, das Verzeichnis der Import-Skripte zu durchsuchen und Importeure zu prüfen, die JSON-Dateien verwenden. Das ist einfacher als die API.

Hallo Tony,

ich stimme dir zu, dass das Hochladen lokaler Dateien über die API etwas knifflig sein kann. Dies sollte funktionieren:

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

client = DiscourseApi::Client.new("Discourse-Website-URL")
client.api_key = "Dein API-Schlüssel"
client.api_username = "Benutzername"

filename = ARGV[1] # Vollständiger Pfad zur Datei /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 ist die ID des Themas, in das du das Bild hochladen möchtest.
args = {
  :topic_id => ARGV[0],
  :raw => "<img src=\"#{url}\" width=\"#{width}\" height=\"#{height}\">"
}

# Dies erstellt einen neuen Beitrag im angegebenen Thema
resp = client.create_post(args)

Dies verwendet das Faraday-Gem, um die erforderlichen Dateiparameter für upload_file bereitzustellen. Sobald die Datei hochgeladen ist, muss sie einem Thema/einem Beitrag zugewiesen werden, damit sie angezeigt wird, andernfalls wird sie automatisch gelöscht.

Du kannst dieses Skript wie folgt aufrufen:

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

Blake,

Vielen, vielen Dank. Ich werde mich jetzt über das Faraday-Gem informieren, um zu verstehen, was es für mich tut, und deinen Skript testen. Ich schätze es wirklich sehr, dass du dir die Zeit genommen hast!

-tony.

Ich habe eine ganze Weile gebraucht, um herauszufinden, wie man den Upload-Endpunkt aus einem Python-Skript aufruft. Zuerst habe ich die Empfehlung befolgt, den Upload-API-Aufruf über die Chrome-Entwicklertools zu reverse-engineeren. Anschließend habe ich den Upload-Aufruf über Postman repliziert. Der zeitaufwändigste Teil für mich war die Übersetzung in funktionierenden Python-Code. Aus irgendeinem Grund funktionierte der von Postman generierte Python-Code ebenfalls nicht. So hat es bei mir schließlich funktioniert:

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