Giter VIP home page Giter VIP logo

uploadcare-ruby's Introduction

Ruby integration for Uploadcare

license Build Status Uploadcare stack on StackShare

Uploadcare Ruby integration handles uploads and further operations with files by wrapping Upload and REST APIs.

Requirements

  • ruby 3.0+

Compatibility

Note that uploadcare-ruby 3.x is not backward compatible with 2.x.

Installation

Add this line to your application's Gemfile:

gem "uploadcare-ruby"

And then execute:

$ bundle

If you use api_struct gem in your project, replace it with uploadcare-api_struct:

gem 'uploadcare-api_struct'

and run bundle install

If already not, create your project in Uploadcare dashboard and copy its API keys from there.

Set your Uploadcare keys in config file or through environment variables:

export UPLOADCARE_PUBLIC_KEY=your_public_key
export UPLOADCARE_SECRET_KEY=your_private_key

Or configure your app yourself if you are using different way of storing keys. Gem configuration is available in Uploadcare.configuration. Full list of settings can be seen in lib/uploadcare.rb

# your_config_initializer_file.rb
Uploadcare.config.public_key = "your_public_key"
Uploadcare.config.secret_key = "your_private_key"

Usage

This section contains practical usage examples. Please note, everything that follows gets way more clear once you've looked through our docs and Upload and REST API refs.

You can also find an example project here.

Uploading files

Uploading and storing a single file

Using Uploadcare is simple, and here are the basics of handling files.

@file_to_upload = File.open("your-file.png")

@uc_file = Uploadcare::Uploader.upload(@file_to_upload, store: "auto")

@uc_file.uuid
# => "dc99200d-9bd6-4b43-bfa9-aa7bfaefca40"

# URL for the file, can be used with your website or app right away
@uc_file.original_file_url
# => "https://ucarecdn.com/dc99200d-9bd6-4b43-bfa9-aa7bfaefca40/your-file.png"

The store option can have these possible values:

  • true: mark the uploaded file as stored.
  • false: do not mark the uploaded file as stored and remove it after 24 hours.
  • "auto": defers the choice of storage behavior to the auto-store setting for your Uploadcare project. This is the default behavior.

Your might then want to store or delete the uploaded file.

# that's how you store a file, if you have uploaded the file using store: false and changed your mind later
@uc_file.store
# => #<Uploadcare::Api::File ...

# and that works for deleting it
@uc_file.delete
# => #<Uploadcare::Api::File ...

Multiple ways to upload files

Uploadcare supports multiple ways to upload files:

# Smart upload - detects type of passed object and picks appropriate upload method
# If you have a large file (more than 100Mb / 10485760 bytes), the uploader will automatically process it with a multipart upload

Uploadcare::Uploader.upload("https://placekitten.com/96/139", store: "auto")

There are explicit ways to select upload type:

files = [File.open("1.jpg"), File.open("1.jpg")]
Uploadcare::Uploader.upload_files(files, store: 'auto')

Uploadcare::Uploader.upload_from_url("https://placekitten.com/96/139", store: "auto")

It is possible to track progress of the upload-from-URL process. To do that, you should specify the async option and get a token:

Uploadcare::Uploader.upload_from_url("https://placekitten.com/96/139", async: true)
# => "c6e31082-6bdc-4cb3-bef5-14dd10574d72"

After the request for uploading-from-URL is sent, you can check the progress of the upload by sending the get_upload_from_url_status request:

Uploadcare::Uploader.get_upload_from_url_status("1251ee66-3631-4416-a2fb-96ba59f5a515")
# => Success({:size=>453543, :total=>453543, :done=>453543, :uuid=>"5c51a7fe-e45d-42a2-ba5e-79957ff4bdab", :file_id=>"5c51a7fe-e45d-42a2-ba5e-79957ff4bdab", :original_filename=>"2250", :is_image=>true, :is_stored=>false, :image_info=>{:dpi=>[96, 96], :width=>2250, :format=>"JPEG", :height=>2250, :sequence=>false, :color_mode=>"RGB", :orientation=>nil, :geo_location=>nil, :datetime_original=>nil}, :video_info=>nil, :content_info=>{:mime=>{:mime=>"image/jpeg", :type=>"image", :subtype=>"jpeg"}, :image=>{:dpi=>[96, 96], :width=>2250, :format=>"JPEG", :height=>2250, :sequence=>false, :color_mode=>"RGB", :orientation=>nil, :geo_location=>nil, :datetime_original=>nil}}, :is_ready=>true, :filename=>"2250", :mime_type=>"image/jpeg", :metadata=>{}, :status=>"success"})

In case of the async option is disabled, uploadcare-ruby tries to request the upload status several times (depending on the max_request_tries config param) and then returns uploaded file attributes.

# multipart upload - can be useful for files bigger than 10 mb
Uploadcare::Uploader.multipart_upload(File.open("big_file.bin"), store: true)

For the multipart upload you can pass a block to add some additional logic after each file chunk is uploaded. For example to track file uploading progress you can do something like this:

file = File.open("big_file.bin")
progress = 0
Uploadcare::Uploader.multipart_upload(file, store: true) do |options|
  progress += (100.0 / options[:links_count])
  puts "PROGRESS = #{progress}"
end

Output of the code above looks like:

PROGRESS = 4.545454545454546
PROGRESS = 9.090909090909092
PROGRESS = 13.636363636363637
...

Options available in a block:

  • :chunk_size - size of each chunk in bytes;
  • :object - file object which is going to be uploaded;
  • :offset - offset from the beginning of a File object in bytes;
  • :link_id - index of a link provided by Uploadcare API. Might be treated as index of a chunk;
  • :links - array of links for uploading file's chunks;
  • :links_count - count of the array of links.

Uploading options

You can override auto-store setting from your Uploadcare project for each upload request:

@api.upload(files, store: true)          # mark the uploaded file as stored.
@api.upload(files, store: false)         # do not mark the uploaded file as stored and remove it after 24 hours.
@api.upload_from_url(url, store: "auto") # defers the choice of storage behavior to the auto-store setting.

You can upload file with custom metadata, for example subsystem and pet:

@api.upload(files, metadata: { subsystem: 'my_subsystem', pet: 'cat' } )
@api.upload_from_url(url, metadata: { subsystem: 'my_subsystem', pet: 'cat' })

File management

Entities are representations of objects in Uploadcare cloud.

File

File entity contains its metadata. It also supports include param to include additional fields to the file object, such as: "appdata".

@file = Uploadcare::File.file("FILE_UUID", include: "appdata")
{
  "datetime_removed"=>nil,
  "datetime_stored"=>"2018-11-26T12:49:10.477888Z",
  "datetime_uploaded"=>"2018-11-26T12:49:09.945335Z",
  "is_image"=>true,
  "is_ready"=>true,
  "mime_type"=>"image/jpeg",
  "original_file_url"=>"https://ucarecdn.com/FILE_UUID/pineapple.jpg",
  "original_filename"=>"pineapple.jpg",
  "size"=>642,
  "url"=>"https://api.uploadcare.com/files/FILE_UUID/",
  "uuid"=>"FILE_UUID",
  "variations"=>nil,
  "content_info"=>{
    "mime"=>{
      "mime"=>"image/jpeg",
      "type"=>"image",
      "subtype"=>"jpeg"
    },
    "image"=>{
      "format"=>"JPEG",
      "width"=>500,
      "height"=>500,
      "sequence"=>false,
      "orientation"=>6,
      "geo_location"=>{
        "latitude"=>55.62013611111111,
        "longitude"=>37.66299166666666
      },
      "datetime_original"=>"2018-08-20T08:59:50",
      "dpi"=>[72, 72]
    }
  },
  "metadata"=>{
    "subsystem"=>"uploader",
    "pet"=>"cat"
  },
  "appdata"=>{
    "uc_clamav_virus_scan"=>{
      "data"=>{
        "infected"=>true,
        "infected_with"=>"Win.Test.EICAR_HDB-1"
      },
      "version"=>"0.104.2",
      "datetime_created"=>"2021-09-21T11:24:33.159663Z",
      "datetime_updated"=>"2021-09-21T11:24:33.159663Z"
    },
    "remove_bg"=>{
      "data"=>{
        "foreground_type"=>"person"
      },
      "version"=>"1.0",
      "datetime_created"=>"2021-07-25T12:24:33.159663Z",
      "datetime_updated"=>"2021-07-25T12:24:33.159663Z"
    },
    "aws_rekognition_detect_labels"=>{
      "data"=>{
        "LabelModelVersion"=>"2.0",
        "Labels"=>[
          {
            "Confidence"=>93.41645812988281,
            "Instances"=>[],
            "Name"=>"Home Decor",
            "Parents"=>[]
          },
          {
            "Confidence"=>70.75951385498047,
            "Instances"=>[],
            "Name"=>"Linen",
            "Parents"=>[{ "Name"=>"Home Decor" }]
          },
          {
            "Confidence"=>64.7123794555664,
            "Instances"=>[],
            "Name"=>"Sunlight",
            "Parents"=>[]
          },
          {
            "Confidence"=>56.264793395996094,
            "Instances"=>[],
            "Name"=>"Flare",
            "Parents"=>[{ "Name"=>"Light" }]
          },
          {
            "Confidence"=>50.47153854370117,
            "Instances"=>[],
            "Name"=>"Tree",
            "Parents"=>[{ "Name"=>"Plant" }]
          }
        ]
      },
      "version"=>"2016-06-27",
      "datetime_created"=>"2021-09-21T11:25:31.259763Z",
      "datetime_updated"=>"2021-09-21T11:27:33.359763Z"
    }
  }
}

@file.local_copy # copy file to local storage

@file.remote_copy # copy file to remote storage

@file.store # stores file, returns updated metadata

@file.delete #deletes file. Returns updated metadata

The File object is also can be converted if it is a document or a video file. Imagine, you have a document file:

@file = Uploadcare::File.file("FILE_UUID")

To convert it to an another file, just do:

@converted_file = @file.convert_document({ format: "png", page: "1" }, store: true)
# => {
#    "uuid"=>"<NEW_FILE_UUID>"}
#    ...other file info...
# }
# OR
# Failure({:"<FILE_UUID>/document/-/format/png/-/page/1/"=>"the target_format is not a supported 'to' format for this source file. <you_source_file_extension> -> png"})

Same works for video files:

@converted_file = @file.convert_video(
  {
    format: "ogg",
    quality: "best",
    cut: { start_time: "0:0:0.1", length: "end" },
    size: { resize_mode: "change_ratio", width: "600", height: "400" },
    thumb: { N: 1, number: 2 }
  },
  store: true
)
# => {
#    "uuid"=>"<NEW_FILE_UUID>"}
#    ...other file info...
# }
# OR
# Failure({:"<FILE_UUID>/video/-/size/600x400/preserve_ratio/-/quality/best/-/format/ogg/-/cut/0:0:0.1/end/-/thumbs~1/2/"=>"CDN Path error: Failed to parse remainder \"/preserve_ratio\" of \"size/600x400/preserve_ratio\""})

More about file conversion here. Metadata of deleted files is stored permanently.

FileList

Uploadcare::FileList represents the whole collection of files (or it's subset) and provides a way to iterate through it, making pagination transparent. FileList objects can be created using Uploadcare::FileList.file_list method.

@list = Uploadcare::FileList.file_list
# Returns instance of Uploadcare::Entity::FileList
<Hashie::Mash
  next=nil
  per_page=100
  previous=nil
  results=[
    # Array of Entity::File
  ]
  total=8>
# load last page of files
@files = @list.files
# load all files
@all_files = @list.load

This method accepts some options to control which files should be fetched and how they should be fetched:

  • :limit — Controls page size. Accepts values from 1 to 1000, defaults to 100.
  • :stored — Can be either true or false. When true, file list will contain only stored files. When false — only not stored.
  • :removed — Can be either true or false. When true, file list will contain only removed files. When false — all except removed. Defaults to false.
  • :ordering — Controls the order of returned files. Available values: datetime_uploaded, -datetime_uploaded. Defaults to datetime_uploaded. More info can be found here.
  • :from — Specifies the starting point for a collection. Resulting collection will contain files from the given value and to the end in a direction set by an ordering option. When files are ordered by datetime_updated in any direction, accepts either a DateTime object or an ISO 8601 string. When files are ordered by size, accepts non-negative integers (size in bytes). More info can be found here.

Options used to create a file list can be accessed through #options method. Note that, once set, they don't affect file fetching process anymore and are stored just for your convenience. That is why they are frozen.

options = {
  limit: 10,
  stored: true,
  ordering: "-datetime_uploaded",
  from: "2017-01-01T00:00:00",
}
@list = @api.file_list(options)

To simply get all associated objects:

@list.all # => returns Array of Files

Pagination

Initially, FileList is a paginated collection. It can be navigated using following methods:

  @file_list = Uploadcare::FileList.file_list
  # Let's assume there are 250 files in cloud. By default, UC loads 100 files. To get next 100 files, do:
  @next_page = @file_list.next_page
  # To get previous page:
  @previous_page = @file_list.previous_page

Alternatively, it's possible to iterate through full list of groups or files with each:

@list.each do |file|
  p file.url
end

Custom File Metadata

File metadata is additional, arbitrary data, associated with uploaded file. As an example, you could store unique file identifier from your system.

# Get file's metadata keys and values.
Uploadcare::FileMetadata.index('FILE_UUID')

# Get the value of a single metadata key.
Uploadcare::FileMetadata.show('FILE_UUID', 'KEY')

# Update the value of a single metadata key. If the key does not exist, it will be created.
Uploadcare::FileMetadata.update('FILE_UUID', 'KEY', 'VALUE')

# Delete a file's metadata key.
Uploadcare::FileMetadata.delete('FILE_UUID', 'KEY')

Group

Groups are structures intended to organize sets of separate files. Each group is assigned UUID. Note, group UUIDs include a ~#{files_count} part at the end. That's a requirement of our API.

# group can be created from an array of Uploadcare files (UUIDs)
@file = "134dc30c-093e-4f48-a5b9-966fe9cb1d01"
@file2 = "134dc30c-093e-4f48-a5b9-966fe9cb1d02"
@files_ary = [@file, @file2]
@group = Uploadcare::Group.create @files

# group can be stored by group ID. It means that all files of a group will be stored on Uploadcare servers permanently
Uploadcare::Group.store(group.id)

# get a file group by its ID.
Uploadcare::Group.rest_info(group.id)

# group can be deleted by group ID.
Uploadcare::Group.delete(group.id)
# Note: This operation only removes the group object itself. All the files that were part of the group are left as is.

GroupList

GroupList is a list of Group

@group_list = Uploadcare::GroupList.list
# To get an array of groups:
@groups = @group_list.all

This is a paginated list, so pagination methods apply

Webhook

https://uploadcare.com/docs/api_reference/rest/webhooks/

You can use webhooks to provide notifications about your uploads to target urls. This gem lets you create and manage webhooks.

Each webhook payload can be signed with a secret (the signing_secret option) to ensure that the request comes from the expected sender. More info about secure webhooks here.

Uploadcare::Webhook.create(target_url: "https://example.com/listen", event: "file.uploaded", is_active: true, signing_secret: "some-secret")
Uploadcare::Webhook.update(<webhook_id>, target_url: "https://newexample.com/listen/new", event: "file.uploaded", is_active: true, signing_secret: "some-secret")
Uploadcare::Webhook.delete("https://example.com/listen")
Uploadcare::Webhook.list
Webhook signature verification

The gem has a helper class to verify a webhook signature from headers — Uploadcare::Param::WebhookSignatureVerifier. This class accepts three important options:

  • :webhook_body — this option represents parameters received in the webhook request in the JSON format. NOTE: if you're using Rails, you should exclude options controller, action and post from the webhook_body.
  • :signing_secret — the secret that was set while creating/updating a webhook. This option can be specified as an ENV var with the name UC_SIGNING_SECRET — then no need to send it to the verifier class.
  • :x_uc_signature_header — the content of the X-Uc-Signature HTTP header in the webhook request.

Using the Uploadcare::Param::WebhookSignatureVerifier class example:

  webhook_body = '{...}'

signing_secret = "12345X"
x_uc_signature_header = "v1=9b31c7dd83fdbf4a2e12b19d7f2b9d87d547672a325b9492457292db4f513c70"

Uploadcare::Param::WebhookSignatureVerifier.valid?(signing_secret: signing_secret, x_uc_signature_header: x_uc_signature_header, webhook_body: webhook_body)

You can write your verifier. Example code:

webhook_body_json = '{...}'

signing_secret = ENV['UC_SIGNING_SECRET']
x_uc_signature_header = "v1=f4d859ed2fe47b9a4fcc81693d34e58ad12366a841e58a7072c1530483689cc0"

digest = OpenSSL::Digest.new('sha256')

calculated_signature = "v1=#{OpenSSL::HMAC.hexdigest(digest, signing_secret.force_encoding("utf-8"), webhook_body_json.force_encoding("utf-8"))}"

if calculated_signature == x_uc_signature_header
  puts "WebHook signature matches!"
else
  puts "WebHook signature mismatch!"
end

Add-Ons

An Add-On is an application implemented by Uploadcare that accepts uploaded files as an input and can produce other files and/or appdata as an output.

AWS Rekognition
# Execute AWS Rekognition Add-On for a given target to detect labels in an image.
# Note: Detected labels are stored in the file's appdata.
Uploadcare::Addons.ws_rekognition_detect_labels('FILE_UUID')

# Check the status of AWS Rekognition.
Uploadcare::Addons.ws_rekognition_detect_labels_status('RETURNED_ID_FROM_WS_REKOGNITION_DETECT_LABELS')
AWS Rekognition Moderation
# Execute AWS Rekognition Moderation Add-On for a given target to detect moderation labels in an image.
# Note: Detected moderation labels are stored in the file's appdata.

Uploadcare::Addons.ws_rekognition_detect_moderation_labels('FILE_UUID')

# Check the status of an Add-On execution request that had been started using the Execute Add-On operation.
Uploadcare::Addons.ws_rekognition_detect_moderation_labels_status('RETURNED_ID_FROM_WS_REKOGNITION_DETECT_MODERATION_LABELS')
ClamAV
# ClamAV virus checking Add-On for a given target.
Uploadcare::Addons.uc_clamav_virus_scan('FILE_UUID')

# Check and purge infected file.
Uploadcare::Addons.uc_clamav_virus_scan('FILE_UUID', purge_infected: true )

# Check the status of an Add-On execution request that had been started using the Execute Add-On operation.
Uploadcare::Addons.uc_clamav_virus_scan_status('RETURNED_ID_FROM_UC_CLAMAV_VIRUS_SCAN')
Remove.bg
# Execute remove.bg background image removal Add-On for a given target.
Uploadcare::Addons.remove_bg('FILE_UUID')

# You can pass optional parameters.
# See the full list of parameters here: https://uploadcare.com/api-refs/rest-api/v0.7.0/#operation/removeBgExecute
Uploadcare::Addons.remove_bg('FILE_UUID', crop: true, type_level: '2')

# Check the status of an Add-On execution request that had been started using the Execute Add-On operation.
Uploadcare::Addons.remove_bg_status('RETURNED_ID_FROM_REMOVE_BG')

Project

Project provides basic info about the connected Uploadcare project. That object is also an Hashie::Mash, so every methods out of these will work.

@project = Uploadcare::Project.project
# => #<Uploadcare::Api::Project collaborators=[], name="demo", pub_key="your_public_key", autostore_enabled=true>

@project.name
# => "demo"

@project.collaborators
# => []
# while that one was empty, it usually goes like this:
# [{"email": [email protected], "name": "Collaborator"}, {"email": [email protected], "name": "Collaborator"}]

Conversion

Video

After each video file upload you obtain a file identifier in UUID format. Then you can use this file identifier to convert your video in multiple ways:

Uploadcare::VideoConverter.convert(
  [
    {
      uuid: "dc99200d-9bd6-4b43-bfa9-aa7bfaefca40",
      size: { resize_mode: "change_ratio", width: "600", height: "400" },
      quality: "best",
      format: "ogg",
      cut: { start_time: "0:0:0.0", length: "0:0:1.0" },
      thumbs: { N: 2, number: 1 }
    }
  ],
  store: false
)

This method accepts options to set properties of an output file:

  • uuid — the file UUID-identifier.
  • size:
    • resize_mode - size operation to apply to a video file. Can be preserve_ratio (default), change_ratio, scale_crop or add_padding.
    • width - width for a converted video.
    • height - height for a converted video.
  NOTE: you can choose to provide a single dimension (width OR height).
        The value you specify for any of the dimensions should be a non-zero integer divisible by 4
  • quality - sets the level of video quality that affects file sizes and hence loading times and volumes of generated traffic. Can be normal (default), better, best, lighter, lightest.
  • format - format for a converted video. Can be mp4 (default), webm, ogg.
  • cut:
    • start_time - defines the starting point of a fragment to cut based on your input file timeline.
    • length - defines the duration of that fragment.
  • thumbs:
    • N - quantity of thumbnails for your video - non-zero integer ranging from 1 to 50; defaults to 1.
    • number - zero-based index of a particular thumbnail in a created set, ranging from 1 to (N - 1).
  • store - a flag indicating if Uploadcare should store your transformed outputs.
# Response
{
  :result => [
    {
      :original_source=>"dc99200d-9bd6-4b43-bfa9-aa7bfaefca40/video/-/size/600x400/change_ratio/-/quality/best/-/format/ogg/-/cut/0:0:0.0/0:0:1.0/-/thumbs~2/1/",
      :token=>911933811,
      :uuid=>"6f9b88bd-625c-4d60-bfde-145fa3813d95",
      :thumbnails_group_uuid=>"cf34c5a1-8fcc-4db2-9ec5-62c389e84468~2"
    }
  ],
  :problems=>{}
}

Params in the response:

  • result - info related to your transformed output(-s):
    • original_source - built path for a particular video with all the conversion operations and parameters.
    • token - a processing job token that can be used to get a job status (see below).
    • uuid - UUID of your processed video file.
    • thumbnails_group_uuid - holds :uuid-thumb-group, a UUID of a file group with thumbnails for an output video, based on the thumbs operation parameters.
  • problems - problems related to your processing job, if any.

To convert multiple videos just add params as a hash for each video to the first argument of the Uploadcare::VideoConverter#convert method:

Uploadcare::VideoConverter.convert(
  [
    { video_one_params }, { video_two_params }, ...
  ],
  store: false
)

To check a status of a video processing job you can simply use appropriate method of Uploadcare::VideoConverter:

token = 911933811
Uploadcare::VideoConverter.status(token)

token here is a processing job token, obtained in a response of a convert video request.

# Response
{
  :status => "finished",
  :error => nil,
  :result => {
    :uuid => "dc99200d-9bd6-4b43-bfa9-aa7bfaefca40",
    :thumbnails_group_uuid => "0f181f24-7551-42e5-bebc-14b15d9d3838~2"
  }
}

Params in the response:

  • status - processing job status, can have one of the following values:
    • pending — video file is being prepared for conversion.
    • processing — video file processing is in progress.
    • finished — the processing is finished.
    • failed — we failed to process the video, see error for details.
    • canceled — video processing was canceled.
  • error - holds a processing error if we failed to handle your video.
  • result - repeats the contents of your processing output.
  • thumbnails_group_uuid - holds :uuid-thumb-group, a UUID of a file group with thumbnails for an output video, based on the thumbs operation parameters.
  • uuid - a UUID of your processed video file.

More examples and options can be found here.

Document

After each document file upload you obtain a file identifier in UUID format.

You can use file identifier to determine the document format and possible conversion formats.

Uploadcare::DocumentConverter.info("dc99200d-9bd6-4b43-bfa9-aa7bfaefca40")

# Response
{:error=>nil, :format=>{
  :name=>"jpg",
  :conversion_formats=>[
    {:name=>"avif"}, {:name=>"bmp"}, {:name=>"gif"}, {:name=>"ico"}, {:name=>"pcx"}, {:name=>"pdf"}, {:name=>"png"}, {:name=>"ps"}, {:name=>"svg"}, {:name=>"tga"}, {:name=>"thumbnail"}, {:name=>"tiff"}, {:name=>"wbmp"}, {:name=>"webp"}
  ]
}}

Then you can use this file identifier to convert your document to a new format:

Uploadcare::DocumentConverter.convert(
  [
    {
      uuid: "dc99200d-9bd6-4b43-bfa9-aa7bfaefca40",
      format: "pdf"
    }
  ],
  store: false
)

or create an image of a particular page (if using image format):

Uploadcare::DocumentConverter.convert(
  [
    {
      uuid: "a4b9db2f-1591-4f4c-8f68-94018924525d",
      format: "png",
      page: 1
    }
  ],
  store: false
)

This method accepts options to set properties of an output file:

  • uuid — the file UUID-identifier.
  • format - defines the target format you want a source file converted to. The supported values are: pdf (default), doc, docx, xls, xlsx, odt, ods, rtf, txt, jpg, png. In case the format operation was not found, your input document will be converted to pdf.
  • page - a page number of a multi-paged document to either jpg or png. The method will not work for any other target formats.
# Response
{
  :result => [
    {
      :original_source=>"a4b9db2f-1591-4f4c-8f68-94018924525d/document/-/format/png/-/page/1/",
      :token=>21120220
      :uuid=>"88fe5ada-90f1-422a-a233-3a0f3a7cf23c"
    }
  ],
  :problems=>{}
}

Params in the response:

  • result - info related to your transformed output(-s):
    • original_source - source file identifier including a target format, if present.
    • token - a processing job token that can be used to get a job status (see below).
    • uuid - UUID of your processed document file.
  • problems - problems related to your processing job, if any.

To convert multiple documents just add params as a hash for each document to the first argument of the Uploadcare::DocumentConverter#convert method:

Uploadcare::DocumentConverter.convert(
  [
    { doc_one_params }, { doc_two_params }, ...
  ],
  store: false
)

To check a status of a document processing job you can simply use appropriate method of Uploadcare::DocumentConverter:

token = 21120220
Uploadcare::DocumentConverter.status(token)

token here is a processing job token, obtained in a response of a convert document request.

# Response
{
  :status => "finished",
  :error => nil,
  :result => {
    :uuid => "a4b9db2f-1591-4f4c-8f68-94018924525d"
  }
}

Params in the response:

  • status - processing job status, can have one of the following values:
    • pending — document file is being prepared for conversion.
    • processing — document file processing is in progress.
    • finished — the processing is finished.
    • failed — we failed to process the document, see error for details.
    • canceled — document processing was canceled.
  • error - holds a processing error if we failed to handle your document.
  • result - repeats the contents of your processing output.
  • uuid - a UUID of your processed document file.

More examples and options can be found here

Secure delivery

You can use custom domain and CDN provider to deliver files with authenticated URLs (see original documentation).

To generate authenticated URL from the library, you should choose Uploadcare::SignedUrlGenerators::AkamaiGenerator (or create your own generator implementation):

generator = Uploadcare::SignedUrlGenerators::AkamaiGenerator.new(cdn_host: 'example.com', secret_key: 'secret_key')
# Optional parameters: ttl: 300, algorithm: 'sha256'
generator.generate_url(uuid, acl = optional)

generator.generate_url("a7d5645e-5cd7-4046-819f-a6a2933bafe3")
# https://example.com/a7d5645e-5cd7-4046-819f-a6a2933bafe3/?token=exp=1649405263~acl=/a7d5645e-5cd7-4046-819f-a6a2933bafe3/~hmac=a989cae5342f17013677f5a0e6577fc5594cc4e238fb4c95eda36634eb47018b

# You can pass in ACL as a second parameter to generate_url. See https://uploadcare.com/docs/security/secure-delivery/#authenticated-urls for supported acl formats
generator.generate_url("a7d5645e-5cd7-4046-819f-a6a2933bafe3", '/*/')
# https://example.com/a7d5645e-5cd7-4046-819f-a6a2933bafe3/?token=exp=1649405263~acl=/*/~hmac=3ce1152c6af8864b36d4dc721f08ca3cf0b3a20278d7f849e82c6c930d48ccc1

# Optionally you can use wildcard: true to generate a wildcard acl token
generator.generate_url("a7d5645e-5cd7-4046-819f-a6a2933bafe3", wildcard: true)
# https://example.com/a7d5645e-5cd7-4046-819f-a6a2933bafe3/?token=exp=1714233449~acl=/a7d5645e-5cd7-4046-819f-a6a2933bafe3/*~hmac=a568ee2a85dd90a8a8a1ef35ea0cc0ef0acb84fe81990edd3a06eacf10a52b4e

# You can also pass in a custom ttl and algorithm to AkamaiGenerator
generator = Uploadcare::SignedUrlGenerators::AkamaiGenerator.new(cdn_host: 'example.com', secret_key: 'secret_key', ttl: 10)
generator.generate_url("a7d5645e-5cd7-4046-819f-a6a2933bafe3")
# This generates a URL that expires in 10 seconds
# https://example.com/a7d5645e-5cd7-4046-819f-a6a2933bafe3/?token=exp=1714233277~acl=/a7d5645e-5cd7-4046-819f-a6a2933bafe3/~hmac=f25343104aeced3004d2cc4d49807d8d7c732300b54b154c319da5283a871a71

Useful links

uploadcare-ruby's People

Contributors

alxgsv avatar dalizard avatar dmitrijivanchenko avatar dmitry-mukhin avatar evgenykungurov avatar geeosh avatar ikukhar avatar kraft001 avatar michaos1 avatar rsedykh avatar steveredka avatar t0mbery avatar vipulnsward avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

uploadcare-ruby's Issues

Installation / usage guide no longer works

Describe the bug

  1. Create a new directory
  2. $ bundle init
  3. Add gem "uploadcare-ruby" to Gemfile
  4. $ bundle install
  5. Try to require uploadcare

Expected behavior

It doesn't crash.

Code / screenshots

Gemfile:

source "https://rubygems.org"

gem "uploadcare-ruby"

main.rb:

require 'uploadcare'

Output from bundle exec ruby main.rb:

/Users/jack/.asdf/installs/ruby/3.1.2/lib/ruby/gems/3.1.0/gems/dry-configurable-0.16.0/lib/dry/configurable/dsl.rb:31:in `setting': wrong number of arguments (given 2, expected 1) (ArgumentError)
	from /Users/jack/.asdf/installs/ruby/3.1.2/lib/ruby/gems/3.1.0/gems/dry-configurable-0.16.0/lib/dry/configurable/class_methods.rb:44:in `setting'
	from /Users/jack/.asdf/installs/ruby/3.1.2/lib/ruby/gems/3.1.0/gems/api_struct-1.0.5/lib/api_struct/settings.rb:5:in `<class:Settings>'
	from /Users/jack/.asdf/installs/ruby/3.1.2/lib/ruby/gems/3.1.0/gems/api_struct-1.0.5/lib/api_struct/settings.rb:2:in `<module:ApiStruct>'
	from /Users/jack/.asdf/installs/ruby/3.1.2/lib/ruby/gems/3.1.0/gems/api_struct-1.0.5/lib/api_struct/settings.rb:1:in `<top (required)>'
	from /Users/jack/.asdf/installs/ruby/3.1.2/lib/ruby/gems/3.1.0/gems/api_struct-1.0.5/lib/api_struct.rb:9:in `require_relative'
	from /Users/jack/.asdf/installs/ruby/3.1.2/lib/ruby/gems/3.1.0/gems/api_struct-1.0.5/lib/api_struct.rb:9:in `<top (required)>'
	from /Users/jack/.asdf/installs/ruby/3.1.2/lib/ruby/gems/3.1.0/gems/uploadcare-ruby-3.3.2/lib/uploadcare/client/rest_client.rb:4:in `require'
	from /Users/jack/.asdf/installs/ruby/3.1.2/lib/ruby/gems/3.1.0/gems/uploadcare-ruby-3.3.2/lib/uploadcare/client/rest_client.rb:4:in `<top (required)>'
	from /Users/jack/.asdf/installs/ruby/3.1.2/lib/ruby/gems/3.1.0/gems/uploadcare-ruby-3.3.2/lib/uploadcare/client/conversion/base_conversion_client.rb:3:in `require_relative'
	from /Users/jack/.asdf/installs/ruby/3.1.2/lib/ruby/gems/3.1.0/gems/uploadcare-ruby-3.3.2/lib/uploadcare/client/conversion/base_conversion_client.rb:3:in `<top (required)>'
	from /Users/jack/.asdf/installs/ruby/3.1.2/lib/ruby/gems/3.1.0/gems/uploadcare-ruby-3.3.2/lib/uploadcare/entity/entity.rb:3:in `require'
	from /Users/jack/.asdf/installs/ruby/3.1.2/lib/ruby/gems/3.1.0/gems/uploadcare-ruby-3.3.2/lib/uploadcare/entity/entity.rb:3:in `block in <top (required)>'
	from /Users/jack/.asdf/installs/ruby/3.1.2/lib/ruby/gems/3.1.0/gems/uploadcare-ruby-3.3.2/lib/uploadcare/entity/entity.rb:3:in `each'
	from /Users/jack/.asdf/installs/ruby/3.1.2/lib/ruby/gems/3.1.0/gems/uploadcare-ruby-3.3.2/lib/uploadcare/entity/entity.rb:3:in `<top (required)>'
	from /Users/jack/.asdf/installs/ruby/3.1.2/lib/ruby/gems/3.1.0/gems/uploadcare-ruby-3.3.2/lib/uploadcare.rb:11:in `require'
	from /Users/jack/.asdf/installs/ruby/3.1.2/lib/ruby/gems/3.1.0/gems/uploadcare-ruby-3.3.2/lib/uploadcare.rb:11:in `<top (required)>'
	from main.rb:1:in `require'
	from main.rb:1:in `<main>'

Gemfile.lock:

GEM
  remote: https://rubygems.org/
  specs:
    addressable (2.8.1)
      public_suffix (>= 2.0.2, < 6.0)
    api_struct (1.0.5)
      dry-configurable
      dry-inflector
      dry-monads (~> 1)
      hashie
      http
    concurrent-ruby (1.1.10)
    domain_name (0.5.20190701)
      unf (>= 0.0.5, < 1.0.0)
    dry-configurable (0.16.0)
      dry-core (~> 0.6)
      zeitwerk (~> 2.6)
    dry-core (0.8.1)
      concurrent-ruby (~> 1.0)
    dry-inflector (0.3.0)
    dry-monads (1.4.0)
      concurrent-ruby (~> 1.0)
      dry-core (~> 0.7)
    ffi (1.15.5)
    ffi-compiler (1.0.1)
      ffi (>= 1.0.0)
      rake
    hashie (5.0.0)
    http (5.1.0)
      addressable (~> 2.8)
      http-cookie (~> 1.0)
      http-form_data (~> 2.2)
      llhttp-ffi (~> 0.4.0)
    http-cookie (1.0.5)
      domain_name (~> 0.5)
    http-form_data (2.3.0)
    llhttp-ffi (0.4.0)
      ffi-compiler (~> 1.0)
      rake (~> 13.0)
    parallel (1.22.1)
    public_suffix (5.0.0)
    rake (13.0.6)
    retries (0.0.5)
    unf (0.1.4)
      unf_ext
    unf_ext (0.0.8.2)
    uploadcare-ruby (3.3.2)
      api_struct (~> 1.0.1)
      dry-configurable (~> 0.9)
      parallel
      retries
    zeitwerk (2.6.1)

PLATFORMS
  x86_64-darwin-21

DEPENDENCIES
  uploadcare-ruby

BUNDLED WITH
   2.3.22

Update webhooks API (event types and versioning)

New event types. Current enum:

  • file.uploaded
  • file.infected (it will be deprecated in favor of info_upldated in the future updates)
  • file.stored
  • file.deleted
  • file.info_updated

https://uploadcare.com/docs/webhooks/#event-types

image

Also, please check the versioning. It's easier to just send current API version, because from within API 0.7 you can't create 0.6 anyways (but you'll be able to create 0.8 when they it is released).

image

Payload is also updated (new initiator field), but since it's not part of the library, nothing is to update here.

p.s. Don't forget to update uploadcare-php-example if necessary.

Operations api

juqery-like chaining api for operations:

@image.rotate(90).resize(200, nil)

and stack-like

@image.operations.add(:rotate, 90)

Ability to use API client instances instead of globally configured instance

I am using uploadcare-ruby in my webservice that works with different Uploadcare projects. In order to switch between project I use this code: https://github.com/alxgsv/uc/blob/main/app/services/uploadcare_service.rb#L5-L14

However, without inspecting sources, I'm not sure that code is thread-safe, and I'm extremely worried about race conditions that could lead to reads or writes to wrong project, violating security and privacy.

It would be great to have an ability to initialize API client and to have guarantee that everything will work as expected:

client = Uploadcare::Api.new(credentials)

uninitialized constant Uploadcare

When I try to upload image Uploadcare::Uploader.upload('https://placekitten.com/96/139')

I get an error:
uninitialized constant Uploadcare

Also when I try to add: require 'uploadcare'

I get an error:

uploadcare-ruby-3.0.5/lib/uploadcare/client/rest_client.rb:12:in `module:Client': uninitialized constant Uploadcare::Client::ApiStruct (NameError)

Client does not support tempfile when it should

I tried the following:

@uc = Uploadcare::Api.new({ ...settings... })
file = params[:file][:tempfile] # this returns a tempfile object
@uc.upload(file)

This blows up with the following error:

Expected `object` to be an Uploadcare::Api::File, an Array or a valid URL string, received: `#<File:0x00007faef4915320>`
uploadcare-ruby-2.1.2/lib/uploadcare/api/uploading_api.rb:13:in `upload'

The error is actually here:

when File then upload_file(object, options)

A tempfile is a file but not of class File so your case equality check fails. Tempfiles should be allowed.

Can't install on Rails 4.1

Howdy,

I get the following when I try to install on a Rails 4.1

Bundler could not find compatible versions for gem "rails":
  In Gemfile:
    filer (>= 0) ruby depends on
      uploadcare-rails (~> 1.0) ruby depends on
        rails (~> 4.0.1) ruby

    filer (>= 0) ruby depends on
      rails (4.1.0)

I deleted my Gemfile.lock and tried to reinstall, but without success.

Thanks for your help!

Update signed URLs implementation to work with ~ and ,

Currently URL like /cd334b26-c641-4393-bcce-b5041546430d~11/nth/1/-/crop/250x250/1000,1000/ won't work when signing a URL, because Akamai escape some symbols.

We use tildas in group URLs, and commas in operations like crop and overlay.

Here is a code snippet how it should work:

function escapeEarly(path) {
  return encodeURIComponent(path)
    .replace(/[~'*]/g, function (c) {
      return '%' + c.charCodeAt(0).toString(16);
    })
    .replace(/%../g, function (match) {
      return match.toLowerCase();
    })
    .replace(/%2c/g, ',')
    .replace(/%20/g, '%2520');
}

Test environment — https://uploadcare.com/docs/security/secure-delivery/#test-environment.

Uploading a URL return sometimes an error

When uploading a URL using @api.upload 'http://....', sometimes I get this error.

NoMethodError: undefined method `names' for nil:NilClass
    from /home/user/.rvm/gems/ruby-2.1.3@app/gems/uploadcare-ruby-1.0.5/lib/uploadcare/utils/parser.rb:45:in `parse'
    from /home/user/.rvm/gems/ruby-2.1.3@app/gems/uploadcare-ruby-1.0.5/lib/uploadcare/utils/parser.rb:13:in `parse_file_string'
    from /home/user/.rvm/gems/ruby-2.1.3@app/gems/uploadcare-ruby-1.0.5/lib/uploadcare/resources/file.rb:7:in `initialize'

Thanks.

Trying to upload from ruby on rails

Trying to upload from ruby on rails

@api = Uploadcare::Api.new({
  public_key: 'xxxxx',

      private_key: 'xxxxxxxxx'

})
@api.upload('uploads/panda-rojo.jpg')

Return is : undefined method `default_settings' for Uploadcare:Module

Dry configurable update

Issue with Dry Configurable

In ruby 3.1 there is this error:
[dry-configurable] default value as positional argument to settings is deprecated and will be removed in the next major version Provide a default: keyword argument instead

These warnings are probably present because the version of dry-configurable gem that is used, has seen plenty of updates. Possibly an update would fix it.

Not a major issue for the time being, but it polutes the log with many warnings. After the deprecation though, it will render it unusable.

Environment

  • Library version: ruby 3.1.2
  • Language/framework version: Rails 7
  • OS version: macOS 12.4

The autorelease github action script does not work

The script that is set for pushing the gem to RubyGems is not working with enabled 2-factor authentication. It would be nice to get it working to automate the release process. Need to edit the script so it could apply OTP-code:

Stack trace:

...
+ exec rake release
uploadcare-ruby 3.1.0 built to pkg/uploadcare-ruby-3.1.0.gem.
Tag v3.1.0 has already been created.
rake aborted!
Pushing gem to https://rubygems.org...
You have enabled multi-factor authentication. Please enter OTP code.
You have enabled multifactor authentication but no OTP code provided. Please fill it and retry.
/usr/local/bundle/gems/rake-13.0.6/exe/rake:27:in `<top (required)>'
Tasks: TOP => release => release:rubygem_push
(See full trace by running task with --trace)

Deprecate PUT /group/{uuid}/storage/

It was deprecated.

image

https://uploadcare.com/api-refs/upload-api/#tag/Groups/operation/filesGroupInfo
https://uploadcare.com/api-refs/rest-api/v0.7.0/#tag/Group/operation/groupInfo

To store or remove files from a group, query the list of files in it, split the list into chunks of 100 files per chunk and then perform batch file storing or batch file removal for all the chunks.

p.s. Don't forget to update https://github.com/uploadcare/uploadcare-rails-example if necessary.

is it really the offical api you support ?

Gemfile :

gem 'uploadcare-ruby'

then bundle install (obviously)

Console (rails c):

@api = Uploadcare::Api.new(CONFIG)

returns

NameError: uninitialized constant Uploadcare

bundle update, retrying via the console, nothing better

Not even trying to understand where this CONFIG thing comes from (looked at the previous issues first - this .yml thing to place "anywhere you want" feels weird).

You might have people willing to pay a cool bunch of dollars every month for your service, but having a gem you can't use straight up from the README might be the last thing to do (in my humble opinion)

Thing is, I'd be still happy to use this tool

Best

Extra slash in API endpoints

Describe the bug

When I do Uploadcare::File.file("2f7f4987-40f1-4e9a-a5dc-3d603b6b00fb"), library makes request to
https://api.uploadcare.com//files/2f7f4987-40f1-4e9a-a5dc-3d603b6b00fb/ instead of
https://api.uploadcare.com/files/2f7f4987-40f1-4e9a-a5dc-3d603b6b00fb/

Expected behavior

Library shouldn't add extra slashes.

Environment

  • Library version: Latest release

file.external_copy does not work with stripped operations

When using file.external_copy('Project-Images', {strip_operations: true}), it should be creating an uncropped version of the image saved to my bucket. However, it is not stripping operations.

As an attempt to work around this, I have made a new, uncropped version of the file and attempted to upload that. It is STILL returning a cropped version. i.e

uncropped_file = @api.file @file.cdn_url_without_operations
copied_file = uncropped_file.external_copy('Project-Images', {})

The copied file is still coming in with the operations attached. This was not happening until yesterday.

I have been outputting the URLs at every point. I have confirmed that uncropped_file is uncropped, but copied_file is not. Since I have turned off storing files, the cdn_url will not be active beyond today, so posting that here will not be useful.

  • Library version: 2.1.1
  • Language/framework version: Ruby
  • OS version: Mac OS 10.15.7

ArgumentError: wrong number of arguments

When I follow the Usage section I'm getting number of errors, please advise

Steps

  • I sign in to my account in app.uploadcare.com,
  • navigate to the files page,
  • click three dots next to the image and
  • select "Copy UUID".
  • This UUID I set in the following example as FILE_ID_IN_YOUR_PROJECT

Then I'm getting the file:

@file = Uploadcare::File.file('FILE_ID_IN_YOUR_PROJECT')

After that I got file object, exactly as in example in Usage section. Next just below the object I can see 2 methods, one is store and one is delete file.

If I type @file.delete or @file.store none of those method are working.

For @file.delete I'm getting exact error I set as title wrong number of arguments. Ok, then I'm passing ID to the delete method: @file.delete(FILE_ID_IN_YOUR_PROJECT) and returning nil. File remain untouched, not deleted

According to the Usage section, I should be able to select file, then delete it with delete method.

Am I doing something wrong?

Version I'm using

gem 'uploadcare-ruby', git: 'git://github.com/uploadcare/uploadcare-ruby', branch: 'feature/1-new-entity-attrs'

I'm using this version because current 3.0.5 returning the error: NameError (uninitialized constant Uploadcare::Client::ApiStruct)
I also tried with 3.1.0.pre.rc1 and getting same error while deleting the file as I described above.

CURL

I tried deleting file with REST API using curl, and got another error

path = '/files/?limit=1&stored=true'
header = Uploadcare::Param::SecureAuthHeader.call(method: 'get', uri: path)
curl -H 'Content-Type: application/json' -H 'Accept: application/vnd.uploadcare-v0.5+json' -H 'Date: #{header[:Date]}' -H 'Authorization: #{header[:Authorization]}' 'https://api.uploadcare.com#{path}'

Got error "{\"detail\":\"Invalid signature. Please check your secret key.\"}" I double checked secret key and generated new one, got same error.

Question is how come I can fetch files @file = Uploadcare::File.file('FILE_ID_IN_YOUR_PROJECT')or upload file with Uploadcare::Api.upload('https://placekitten.com/96/139')

Proposal: add #files and #groups methods to Uploadcare::Api

Currently the only two options of using the GET /files//GET /groups/ API endpoints are:

  • api.file_list(oprions) that performs params validation and returns a smart Uploadcare::Api::ResourceList which user might not need
  • api.get("/files/", oprions) that performs no validation, returns raw API response and requires user to know the endpoint URLs

My proposal is to add two methods: api.files(options) and api.groups(options) that both will return raw API responces but perform same validations as api.file_list/api.group_list does and encapsulate the endpoint URLs

This will provide users with a convinient alternative to api.get("/files/"). Оffcource they will still have to use api.get(response['next']) in order to fetch next pages.

Bulk upload files via upload_files method in Uploadcare::Api is returning files out of order.

I have a PDF that I'm chopping up into jpegs on my backend, which I then upload in bulk to Uploadcare, but noticed that I'm receiving the images back out of order.

I can sort the images back on my end because I've named them 0.jpg, 1.jpg, etc., however, the Uploadcare::Api::File object that I get in return doesn't contain the name of the original image unless I get that information via the load_data method, which requires me to make multiple round trips to the Uploadcare API for each image, which isn't ideal.

Any suggestions on how I can upload in bulk to preserve the order, or at least get the name of the original file that in the file object that gets returned from uploadcare?

Deleting a file results in `RequestError::Unauthorized` even though deletion is successful

When deleting a file using the gem a RequestError::Unauthorized exception is
thrown, even though the API client is configured with the correct keys and it's
possible to make other API calls. The file appears to be deleted successfully.

On DELETE the API responds with a 302 pointing the client to the original File
resource, and it's when following the redirect that the client raises the error.

Steps to reproduce

  • Create an Uploadcare API client using valid public and private keys
  • Create a new file object using the client.
  • Call file.load_data! to confirm that authentication is working
  • Call file.delete and see a 401 error

Code to reproduce

file_id = "a-valid-uuid"
file = api.file(file_id)
file.load_data!
begin
  file.delete
rescue Uploadcare::Error::RequestError::Unauthorized => e
  puts "Rescued a 401 on file deletion" # this always happens
  file = api.file(file_id)
  file.load_data! # we can still load it
  puts file.deleted? # will return true
end

Error requiring "uploadcare"

Requiring "uploadcare" is causing non-deterministic issues in our Heroku Rails app's build process. Here is the stack trace:

/gems/uploadcare-ruby-3.1.0/lib/uploadcare/client/project_client.rb:7 in <module:Client>
/gems/uploadcare-ruby-3.1.0/lib/uploadcare/client/project_client.rb:4 in <module:Uploadcare>
/gems/uploadcare-ruby-3.1.0/lib/uploadcare/client/project_client.rb:3 in <main>
/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23 in require
/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23 in block in require_with_bootsnap_lfi
/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/loaded_features_index.rb:92 in register
/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22 in require_with_bootsnap_lfi
/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31 in require
/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325 in block in require
/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:291 in load_dependency
/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325 in require
/gems/uploadcare-ruby-3.1.0/lib/uploadcare/entity/entity.rb:3 in block in <main>
/gems/uploadcare-ruby-3.1.0/lib/uploadcare/entity/entity.rb:3 in each
/gems/uploadcare-ruby-3.1.0/lib/uploadcare/entity/entity.rb:3 in <main>
/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23 in require
/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23 in block in require_with_bootsnap_lfi
/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/loaded_features_index.rb:92 in register
/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22 in require_with_bootsnap_lfi
/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31 in require
/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325 in block in require
/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:291 in load_dependency
/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325 in require
/gems/uploadcare-ruby-3.1.0/lib/uploadcare.rb:11 in <main>
/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23 in require
/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23 in block in require_with_bootsnap_lfi
/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/loaded_features_index.rb:92 in register
/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22 in require_with_bootsnap_lfi
/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31 in require
/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325 in block in require
/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:291 in load_dependency
/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325 in require
config/initializers/uploadcare_service.rb:1 in <main>

require 'uploadcare'
...

For whatever reason, this seems to only happen 20% of the time. Re-deploying seems to work, but this has gotten quite annoying.

I load uploadcare in my initializers like so:

config/initializers/uploadcare.rb

require 'uploadcare'

Uploadcare.config.public_key = ENV["UPLOADCARE_PUBLIC_KEY"]
Uploadcare.config.secret_key = ENV["UPLOADCARE_SECRET_KEY"]

Reimplement the `ResourceList#[]` method to prevent LSP violation

Currently Uploadcare::Api::ResourceList objects (Uploadcare::Api::FileList, Uploadcare::Api::GroupList) are working like so:

list = api.file_list(limit: 10)

list[0] # => #<Uploadcare::Api::File ...>
# but
list[10] # => nil (since only first 10 files were loaded so far)
# but
list.first(11).last # => #<Uploadcare::Api::File ...>

This happens because Uploadcare::Api::ResourceList delegates #[] method to #objects (array of currently loaded objects), so the requested object will only be returned if it was loaded so far.

It seems to me that this behaviour violates the least surprise principle: the expected behaviour for list[10] is to return the requested element of the list (triggering next page requests if needed) or nil

So how about reimplementing the #[] method to conform with this expectation, for exampe like so:

def [](index)
  first(index+1).last
end

REQ: Memory Reduction - replace mime-types with mini_mime

BACKGROUND:
Mime-types is a large, memory intensive gem. Example of allocated memory via derailed bundle:objects:

allocated memory by gem
-----------------------------------
  30106245  activesupport-5.2.1
   6303003  mime-types-3.2.2
   1771271  addressable-2.6.0
   1748528  activerecord-5.2.1
  ...

The equivalent functionality can be accomplished without incurring so much memory overhead using mini_mime gem.

See this issue on mini_mime for details on how to reduce. Major projects are already adopting.
discourse/mini_mime#6

Figaro: key not found: "UPLOADCARE_PUBLIC_KEY"

key not found: "UPLOADCARE_PUBLIC_KEY"

When using Figaro for storing keys in application.yml I get the following error message when running rails c or rails s:

/Users/xx/.rvm/gems/ruby-3.1.2/gems/uploadcare-ruby-4.2.0/lib/uploadcare.rb:48:in `fetch': key not found: "UPLOADCARE_PUBLIC_KEY" (KeyError)

from /Users/xx/.rvm/gems/ruby-3.1.2/gems/uploadcare-ruby-4.2.0/lib/uploadcare.rb:48:in `<module:Uploadcare>'

It works when I manually import the keys like so

export UPLOADCARE_PUBLIC_KEY=your_public_key
export UPLOADCARE_SECRET_KEY=your_private_key

But I get the following warning + I have to manually export keys on every new terminal I work on:

WARNING: Skipping key "UPLOADCARE_PUBLIC_KEY". Already set in ENV.
WARNING: Skipping key "UPLOADCARE_SECRET_KEY". Already set in ENV.

uploadcare.rb

Uploadcare::Rails.configure do |config|
  config.public_key = ENV.fetch('UPLOADCARE_PUBLIC_KEY', 'demopublickey')
  config.secret_key = ENV.fetch('UPLOADCARE_SECRET_KEY', 'demosecretkey')
 ...
end

Expected behavior

I should be able to set the variables in application.yml

Code / screenshots

Environment

gemfile.lock

uploadcare-rails (3.2.0)
      rails (>= 4)
      uploadcare-ruby (>= 4.2)
uploadcare-ruby (4.2.0)
      api_struct (~> 1.0.1)
      mimemagic
      parallel
      retries
dry-configurable (= 0.13.0)

ruby-3.1.2

rails, 6.1.6

`Uploadcare::File#delete` is not deleting the file.

Describe the bug

Uploadcare::File#delete is not deleting the file.

Using the doc reference

file = Uploadcare::File.file("FILE_ID_IN_YOUR_PROJECT")
file.detele # return file json, but nothing happens.

Newly updated images

file = File.open(file_path)
uc_file = Uploadcare::Uploader.upload(file)
Uploadcare::File.delete(uc_file.uiid) # don't delete the file
uc.delete # also don't delete the file

Environment

  • Library version: 4
  • Language/framework version: Ruby 3.0.3
  • OS version: MacOs Venture

API KEY?

where it is placed in Ruby on Rails API KEY?

Use api_struct style of settings

Brief description of the feature and motivation behind it

Gem api_struct uses endpoints in its configuration, but uploadcare-ruby gem overwrites it and introduces its own way of configuration.

If we don't need to change API root urls, it may be a good idea to switch to the native api_struct configuration style

Prevent duplicate uploads from same URL

How can I use the options check_URL_duplicates and save_URL_duplicates with Uploadcare::Api? I tried multiple ways, but the API settings don't seem to acknowledge these options.

Deprecation and warning messages on the latest version.

Describe the bug

Is not a bug per se, but the latest version of the gem is giving me a couple of warning and deprecation messages loading the gem or using the API

[2] pry(main)> require 'uploadcare'
/Users/ricardoperez/.rvm/gems/ruby-3.0.3/gems/api_struct-1.0.5/lib/api_struct/settings.rb:2:in `<module:ApiStruct>' [dry-configurable] default value as positional argument to settings is deprecated and will be removed in the next major version
Provide a `default:` keyword argument instead
  • Using the API
[3] pry(main)> Uploadcare::File.file(UUID)
W, [2023-02-22T16:57:04.953697 #27459]  WARN -- : You are setting a key that conflicts with a built-in method Hashie::Mash#size defined in Hash. This can cause unexpected behavior when accessing the key as a property. You can still access the key via the #[] method.

Environment

  • Library version: 4.0 (dry-configurable '0.13.0')
  • Language/framework version: 3.0.3
  • OS version: macOs Ventura

RequestError with no messasge is thrown when max_request_tries is exceeded

Describe the bug

If an upload request fails due to exceeding the max number of retries, Uploadcare::Exception::RequestError is thrown without a message, which makes it difficult to debug.

Steps to reproduce

  • Set max_request_tries to 1
  • Upload a file from URL: Uploadcare::Uploader.upload(url)
  • In some cases, it will fail with Uploadcare::Exception::RequestError because max_request_tries also limits the number of requests to /from_url/status/

Expected behavior

Uploadcare::Exception::RequestError provides a message describing the failure reason OR max_request_tries doesn't limit the number of status polling requests

Signed URLs updates

I want uploadcare-ruby to have the same signed URL capabilities as pyuploadcare. Correct me if this is something wrong to do (or already done, or requires to build something else).


Implement generating URL tokens for signed URLs

Currently, the lib allows for generating ACL tokens only. Akamai supports two type of tokens: ACL and URL. See https://github.com/akamai/EdgeAuth-Token-Python/blob/master/akamai/edgeauth/edgeauth.py for reference.

Allow to pass a UUID + params when generating signed URL (ACL)

Currently, the AkamaiSecureUrlBuilder class allows for signing a whole URL. In some cases, there's a need to generate a universal ACL token with wildcards. For example, we can specify an ACL as follows:

/{uuid}/*

and the token generated will be applicable to any variation of the file associated with the {uuid}. E.g., https://ucarecdn.com/{uuid}/-/resize/360x/-/format/auto/

See https://github.com/akamai/EdgeAuth-Token-Python/blob/master/akamai/edgeauth/edgeauth.py#L183 for reference.


You can use pyuploadcare implementation as a reference:

TypeError after upgrading from Rails 4.x to 5.2

Upgraded from Rails 4.x to 5.2 and seeing the following error:

2.4.1 :003 > UploadcareApi.upload_from_url "https://image-ticketfly.imgix.net/00/02/90/44/99-og.jpg"
2.4.1 :009 > file.uuid
 => "27e81883-6444-45a5-b8f2-f0070a93bade" 
2.4.1 :010 > file.cdn_url
 => "https://ucarecdn.com/27e81883-6444-45a5-b8f2-f0070a93bade/" 
2.4.1 :011 > file.store
TypeError: no implicit conversion of nil into String

Implement ResourceList#each_page method

Currently when you want to do something with each page you'll need to do something like this:

list = api.file_list(limit: 10)

list.each_slice(10) do |page_of_10_files|
  # do something with the page
end

The issue here is that someone outside of the file list needs to know the :limit value to synchronize each_slice with page fetching requests.

Offcource there is a FileList#options method, but it'll contain the :limit option only when it was set during the list instantiation.

This is not a blocker for the release but rather a small convinience that can be implemented later

MIME type of uploaded files is always "application/octet-stream"

Describe the bug

Ruby client always uploads files with mime_type=application/octet-stream:

ENV["UPLOADCARE_PUBLIC_KEY"] = "pub_key"
ENV["UPLOADCARE_SECRET_KEY"] = "secret"
require "uploadcare"

@file_to_upload = File.open("your-file.png")
@uc_file = Uploadcare::Uploader.upload(@file_to_upload)
@uc_file.mime_type

# => "application/octet-stream"

Expected behavior

Other UC clients provide an original mime_type of uploaded file, e.g.:

$ curl -F "UPLOADCARE_PUB_KEY=pub_key" -F "[email protected]" "https://upload.uploadcare.com/base/"

# {"file":"43f09fdb-28b1-4785-b1d1-3c5fd6217549"}

$ curl -H "Authorization: Uploadcare.Simple pub_key:secret" "https://api.uploadcare.com/files/43f09fdb-28b1-4785-b1d1-3c5fd6217549/" | json_pp | grep mime

#   "mime_type" : "image/jpeg",
from pyuploadcare import File, Uploadcare

uploadcare = Uploadcare(public_key='pub_key', secret_key='secret')
with open('cat.jpg', 'rb') as file_object:
     uc_file: File = uploadcare.upload(file_object)
     print(uc_file.mime_type)

# image/jpeg

Code / screenshots

Environment

  • Library version: 3.3.2
  • Language/framework version: 2.7.0p0
  • OS version: Ubuntu 20.04.4 LTS

Add pub_key to user agent header.

This is very helpful for supporting our users both retro- and proactively.

User agent should be: "uploadcare-ruby/{ruby version}/{gem version}/{pub_key}

Leave a way for user to set User agent to their liking.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.