RocketChat / Rocket.Chat.js.SDK

Utility for apps and bots to interact with Rocket.Chat via DDP and/or API
MIT License
135 stars 95 forks source link

Upload file header #92

Open kakerduu opened 5 years ago

kakerduu commented 5 years ago

Greetings,

I'm using the POST API call to upload a file in rocketchat, which will be set as an icon, logo afterwards.

Problem is that the default POST call is using application/json, but the file, which is an image, should be treated as multipart/form-data file.

Any suggestions how to change the header in that call?

Thank you in advance.

galshiff commented 5 years ago

We need this too, +1 for attention

djlazz3 commented 4 years ago

you can change the header by setting api.basicHeaders['Content-Type'] = 'multipart/form-data; boundary=' however, im still trying to figure out how to generate the boundary part

djlazz3 commented 4 years ago

although it may be technically possible to do this using the api interface, I ended up deciding to use the driver websocket interface, and it worked way better...

driver.sendMessage({
  msg: "Message goes here",
  rid: "RoomID goes here",
  attachments: [{
    fields: [{
      value: "File goes here"
    }],
    text: "File description goes here"
  }]
})

there are more fields that are allowed, these are just the ones that i used, for the full list of fields, take a look at https://github.com/RocketChat/Rocket.Chat.js.SDK/blob/e507e86faf049751218a08f6488545ec77d33309/src/config/messageInterfaces.ts#L3

nivoliev commented 4 years ago

@djlazz3 can you be a bit more specific about the "File goes here" part ? I'm trying to simply post an image, I thought I got it to work with a message of the form :

{
  title: "some title",
  attachments : [{
    image_url: "data:image/png;base64,..."
  }]
}

but the android app does not handle data uris. I've tried since then to use an api post at rooms.upload but I can't get it to work, I get answered that application/json is not supported. I got it to work using curl or python requests, but that's really ugly. Thanks for any help !

nivoliev commented 4 years ago

I finally managed to upload using the following code. Note that this was done in the context of a hubot robot, and I finally used its integrated http client which is an instance of a scoped-http-client, since the http client provided with this sdk messed up with the payload I built.

const upload = (robot, room, data) => {
  //data layout
  //{
  //  contents : filedata to upload
  //  format : format of the data, passed to Buffer.from
  //  mime : mime type of the data
  //  filename : name of the destination file on the chat
  //  options : { added as additional fields in the formdata
  //    key : value
  //  }
  //}

  //thanks to https://gist.github.com/tanaikech/40c9284e91d209356395b43022ffc5cc

  //build formdata for the data
  const uid = require('uid-safe') ;
  let boundary = uid.sync(18) ;
  let form = "" ;

  //options
  if(data.options) {
    for(const opt in data.options) {
      if({}.hasOwnProperty.call(data.options, opt)){
        form += `--${boundary}\r\n` ;
        form += `Content-Disposition: form-data; name="${opt}";\r\n\r\n${data.options[opt]}\r\n` ;
      }
    }
  }

  //file upload
  form += `--${boundary}\r\n` ;
  form += `Content-Disposition: form-data; name="file"; filename=${data.filename}\r\n` ;
  form += `Content-Type: ${data.mime}\r\n\r\n` ;

  const payload = Buffer.concat([
    Buffer.from(form, 'utf-8'),
    Buffer.from(data.contents, data.format),
    Buffer.from(`\r\n--${boundary}--\r\n`, 'utf-8')
  ])

  //not able to post fully through robot.adapter.api, the payload is messed up
  //api login
  robot.adapter.api.login().then( (ack) => {
    //api upload
    robot.http(robot.adapter.api.url)
    .header('X-User-Id', ack.data.userId)
    .header('X-Auth-Token', ack.data.authToken)
    .path(`rooms.upload/${room}`)
    .header('Content-Type', `multipart/form-data; boundary=${boundary}`)
    .post(payload)((err, response, body) => {
      if(err) {
        error.log(err) ;
      }
    })
  }) ;
}