crisp-im/node-crisp-api

How to use Bucket for uploading image via API

ehsan-mohammadi opened this issue · 19 comments

Hello again!
I want to upload an image with Bucket. In this way, I used crispClient.bucket.generateBucketURL(data). But it returns me 403 - not_allowed error.
I tried this code:

var data = {
    namespace: "upload",
    from: "plugin",
    identifier: crispConfig.plugin.identifier,
    id: "bal2",
    file: {
      name: input.file.name,
      type: input.file.type
    }
};

crispClient.bucket.generateBucketURL(data)

I used my plugin identifier and key for this code.
Also, can you help me how can I upload a photo after generating the bucket URL?

Thanks a lot

Hello!

  • Do you have the required scope on the Marketplace for your API token? (bucket scope)
  • Can you try swap the values of id and identifier and see if that works?
  • Can you double check that your plugin ID that you are passing matches your current API token plugin ID? There’s strong authenticity verification on that.

@valeriansaliou Yes, I added Bucket scope to my plugin in the Marketplace. Also, I double-checked my plugin identifier and finally, re-created the identifier and key in the Marketplace. Maybe, everything is fine and I haven't any idea about the problem.
If I want to upload a photo from plugin, should I put the plugin-identifier that I got from Marketplace, in the message body?

var data = {
    namespace: "upload",
    from: "plugin",
    identifier: crispConfig.plugin.identifier, // The identifier that I got from Crisp Marketplace
    ...
}

Did you publish your plugin? That’s probably the issue, I believe this can’t work if you don’t first publish your plugin to obtain a permanent identifier for the plugin (this is an UUID, not the plugin URN).

@valeriansaliou Yes, I published it as a private plugin and use production token.

Here's an example code from one of our plugin (w/ the Golang library):

  _, err := httpEndpointManager.crisp.client.Bucket.GenerateBucketURL(crispAPI.BucketURLRequest{
    Namespace  : "upload",
    From       : "plugin",
    Identifier : httpEndpointManager.crisp.pluginID, // your plugin_id (an UUID, not an URN)
    ID         : correlationID, // an internal ID that you generate to match the signed URL generated event coming back on the RTM API

    File       : crispAPI.BucketURLRequestFile {
      Name : fileName, // eg. "Photo.jpg"
      Type : fileType, // eg. "image/jpeg"
    },
  })

@valeriansaliou Many thanks for helping me!
I did a mistake because I used production-identifier instead of UUID.
Now, in the RTM bucket:url:upload:generated event, I get this message:

{
  identifier: 'my identifier',
  type: 'upload',
  from: 'plugin',
  url: {
    signed: 'signed URL'
    resource: 'resource URL'
  },
  policy: { size_limit: 12000000 },
  id: 'bal2'
}

But if I enter signed-url in the browser, it gives me this message:

Oops! This file is not reachable.
It may have expired as it was too old, or was removed by our systems because it could be harmful.

How can I reach the photo that I upload it?

Great!

You need first to upload it using url.signed by doing an HTTP PUT w/ your file content, with the exact same name and MIME type as requested (as this is verified upon upload, it needs to match).

Then, once the file is uploaded by your HTTP client (can be a Web browser or your server), your file will be available at url.resource.

Note that we run a cache layer on our edges that could cache the 404 Not Found if you try to open url.resource before the file gets uploaded with url.signed. So upload it first, and then you can read the file anytime.

Also note that any image uploaded will be downsized, we do not keep originals.

@valeriansaliou Many thanks for helping me and quick response! That solved my problem.
Also, thanks to the Crisp team!

@valeriansaliou Can you help me with the standard format of the file content that should be uploaded in the url.signed?
For example, I send messages with this structure:

var message = {
    origin: 'chat',
    type: 'text',
    from: 'operator',
    content: 'Some content'
};

Should I send my file in a format like this?
What's the right format of my file content (like base64)
I want to upload it with the <input type="file">.

You need to PUT to the signed URL.

Send send the unsigned URL resource as content.url in the message, with type file. The content body should also contain name and type as per our docs.

@valeriansaliou Is this correct?

var file: {
    type: 'image/jpeg',
    name: 'sample.jpeg',
    url: 'Unsigned resource URL',
};

Then I do a PUT request to the signed URL. But, where should I put the file binary (or base64 or other formats) content?

Yes, LGTM.

@valeriansaliou So, where should I set the file binary? These are just settings (type, name, and URL).

Can you give me an example?

The file should be uploaded to the signed URL you get, using a standard HTTP file upload via HTTP PUT.

@valeriansaliou Oh, sorry for my bad mistake. Thanks a lot for helping me.

Somewhat related question, is there a way for us to provide our own signed URL for Crisp to use for uploading?

e.g. I have https://untrusted.files.ai.moda/api/v1.0.0-alpha/url/generate that generates a presigned upload URL.

You could just upload your file on your signed and use the bucket URL in the Crisp message, no need to use the bucket API, as its only used to upload files on Crisp.

Hmm, isn't that only useful for operator -> user? I want user attachments -> operator to use a different endpoint.

image