Télécharger une image locale en utilisant l'API

Salut tout le monde,

J’espère que c’est le bon endroit pour poser ma question. Je travaille à l’importation d’un ensemble de données provenant d’un autre forum vers notre nouvelle instance Discourse (des posts internes de connaissances que nous souhaitons migrer).

J’ai soigneusement regroupé nos anciennes données dans plusieurs structures JSON, mais je bloque sur le téléchargement des diverses images liées aux anciens posts.

J’utilise le gem discourse_api et j’ai eu beaucoup de succès jusqu’ici, même si je réalise qu’il est incomplet. Je peux télécharger une image avec succès si elle est hébergée quelque part, comme ceci :

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

mais je suis bloqué lorsque j’essaie de télécharger une image située sur ma machine locale :

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

…ce qui retourne l’erreur suivante :

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'

J’ai assez fouillé pour réaliser que je dois probablement effectuer une manipulation en base64 ou autre afin que ma requête soit correctement formée (je réalise aussi que peut-être la méthode de téléchargement du gem Ruby ne peut tout simplement pas prendre en charge ce type de téléchargement, et si c’est le cas, ce n’est pas grave).

Je cherche surtout des conseils, pour voir si d’autres personnes ont rencontré ce problème et pour savoir si je me trompe complètement de piste. Merci d’avance, et tout le reste :slight_smile:

Sauf si vous avez une raison de ne pas le faire, je vous recommande de consulter le répertoire du script d’importation pour voir les importateurs qui utilisent des fichiers JSON. Ce sera plus simple que l’API.

Salut Tony,

Je conviens que le téléchargement de fichiers locaux peut être un peu délicat à comprendre via l’API. Voici ce qui devrait fonctionner :

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

client = DiscourseApi::Client.new("URL du site Discourse")
client.api_key = "Votre clé API"
client.api_username = "Nom d'utilisateur"

filename = ARGV[1] # chemin complet vers le fichier /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 est l'identifiant du sujet dans lequel vous souhaitez télécharger l'image.
args = {
  :topic_id => ARGV[0],
  :raw => "<img src=\"#{url}\" width=\"#{width}\" height=\"#{height}\">"
}

# Cela créera un nouveau message dans le sujet spécifié
resp = client.create_post(args)

Ce script utilise la gemme Faraday pour fournir les exigences de fichier correctes pour upload_file. Une fois le fichier téléchargé, il doit être attribué à un sujet ou un message pour s’afficher, sinon il sera automatiquement supprimé.

Vous pouvez exécuter ce script avec :

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

Blake,

Un grand merci. Je vais me renseigner sur le gem Faraday pour comprendre ce qu’il fait pour moi et tester ton script. Je te suis vraiment reconnaissant d’avoir pris le temps de m’aider !

-tony.

J’ai passé pas mal de temps à essayer de comprendre comment appeler le point de terminaison d’upload depuis un script Python. J’ai d’abord suivi la recommandation consistant à analyser le appel API d’upload via les outils de développement de Chrome. Ensuite, j’ai reproduit cet appel via Postman. La partie la plus chronophage pour moi a été de traduire cela en un code Python fonctionnel. Pour une raison quelconque, le code Python généré par Postman ne fonctionnait pas non plus. Voici comment cela a finalement fonctionné pour moi :

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