cloudinary 1.29.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0ec56a8224fa9a3318d7e0d3e7ce7747c888767a4b365a752310e38b7747f4a3
4
- data.tar.gz: 58f0148449592fb70e8a87bc292ddeea43a09b0f879fca9c62c1594b3ff487cc
3
+ metadata.gz: 6d6f32cb53d97a60e6d0ec304b1dbee2a80e7d1610c9007a9a0331bf80c3f882
4
+ data.tar.gz: 29863f2c682c9800cef486624985a8d4f8959b7da19ce0f53b4377bdc0312eaf
5
5
  SHA512:
6
- metadata.gz: 44e6c4cefaebd3853f8da9c40123d05205b6fa57fd58eb22e1a8a419bad658b3184eb2bd068f79b8d54601793295c333e6a02720d6a5bdbcb699b234432603e2
7
- data.tar.gz: de7032533e031e15c51ccc17ff8e77a2aabc6f9aea4958a58d2313b30aeadc8b14574e36090c99a9e58788e3a376bc9330cfdd0e8d77fcb96d3d4deea7cbfd57
6
+ metadata.gz: 8b7ac1b9edaeb3d8faad6dc1d75442f41cadef751400840c27ff176d370ca0739f68eda398c05efe56b7bfaa04376a0154f17840e15ac670fd4cc9d673527cb0
7
+ data.tar.gz: c3ba9122af7accec3abf2b9388b62be44e1e483a6f229e13ba40d1d283e9eef75c7179235b2674011e7d49d1fc12284c83b59f0dcfb0eed38e73195815123294
data/.travis.yml CHANGED
@@ -1,7 +1,6 @@
1
1
  dist: jammy
2
2
  language: ruby
3
3
  rvm:
4
- - 2.7.8
5
4
  - 3.1.4
6
5
  - 3.2.2
7
6
  - 3.3.0
data/CHANGELOG.md CHANGED
@@ -1,3 +1,36 @@
1
+ 2.0.0 / 2024-04-08
2
+ ==================
3
+
4
+ Breaking Changes
5
+ ----------------
6
+
7
+ * Set minimal Ruby version to `3.0`
8
+ * For older Rubies use version `1.x` of this library
9
+ * Replace `rest-client` with `faraday`
10
+ * Set config `secure` to `true` by default
11
+ * All delivery URLs are set to be `https://` by default
12
+ * To disable - set `secure` to `false` in config/options
13
+ * Add support for URL Analytics
14
+ * Adds analytics signature query parameter to the delivery URLs
15
+ * To disable - set `analytics` to `false` in config/options
16
+ * Remove deprecated methods
17
+ * `Cloudinary::Utils.unsigned_download_url`
18
+ * use `Cloudinary::Utils.cloudinary_url` instead
19
+ * `Cloudinary::Utils.signed_download_url`
20
+ * use `Cloudinary::Utils.cloudinary_url` instead
21
+ * `Cloudinary::Utils.zip_download_url`
22
+ * use `Cloudinary::Utils.download_zip_url` instead
23
+ * `cl_zip_download_url`
24
+ * use `cl_download_zip_url` instead
25
+ * Remove deprecated constants
26
+
27
+ New functionality and features
28
+ ------------------------------
29
+
30
+ * Add support for `analyze` API
31
+ * Support chunked uploads with CarrierWave
32
+ * Filter users by last login in `users` Provisioning API
33
+
1
34
  1.29.0 / 2024-02-26
2
35
  ==================
3
36
 
data/README.md CHANGED
@@ -40,11 +40,13 @@ the [Ruby on Rails SDK Guide](https://cloudinary.com/documentation/rails_integra
40
40
 
41
41
  | SDK Version | Ruby 1.9.3 | Ruby 2.x | Ruby 3.x |
42
42
  |-------------|------------|----------|----------|
43
- | 1.x | v | v | v |
43
+ | 1.x | | | |
44
+ | 2.x | ✘ | ✘ | ✔ |
44
45
 
45
46
  | SDK Version | Rails 5.x | Rails 6.x | Rails 7.x |
46
47
  |-------------|-----------|-----------|-----------|
47
- | 1.x | v | v | v |
48
+ | 1.x | | | |
49
+ | 2.x | ✘ | ✔ | ✔ |
48
50
 
49
51
  ## Installation
50
52
 
@@ -64,7 +66,7 @@ require 'cloudinary'
64
66
  - [See full documentation](https://cloudinary.com/documentation/rails_image_manipulation).
65
67
 
66
68
  ```ruby
67
- cl_image_tag("sample.jpg", :width => 100, :height => 150, :crop => :fill)
69
+ cl_image_tag("sample.jpg", width: 100, height: 150, crop: "fill")
68
70
  ```
69
71
 
70
72
  ### Upload
data/cloudinary.gemspec CHANGED
@@ -7,63 +7,33 @@ Gem::Specification.new do |s|
7
7
  s.version = Cloudinary::VERSION
8
8
  s.authors = ["Nadav Soferman","Itai Lahan","Tal Lev-Ami"]
9
9
  s.email = ["nadav.soferman@cloudinary.com","itai.lahan@cloudinary.com","tal.levami@cloudinary.com"]
10
- s.homepage = "http://cloudinary.com"
10
+ s.homepage = "https://cloudinary.com"
11
11
  s.license = "MIT"
12
12
 
13
13
  s.summary = %q{Client library for easily using the Cloudinary service}
14
14
  s.description = %q{Client library for easily using the Cloudinary service}
15
15
 
16
- s.rubyforge_project = "cloudinary"
17
-
18
- s.files = `git ls-files`.split("\n").select { |f| !f.start_with?("test", "spec", "features", "samples") } + Dir.glob("vendor/assets/javascripts/*/*") + Dir.glob("vendor/assets/html/*")
16
+ s.files = `git ls-files`.split("\n").select { |f| !f.start_with?("test", "spec", "features", "samples") } +
17
+ Dir.glob("vendor/assets/javascripts/*/*") + Dir.glob("vendor/assets/html/*")
19
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
19
  s.require_paths = ["lib"]
21
20
 
22
- s.add_dependency "aws_cf_signer"
23
-
24
- if RUBY_VERSION >= "2.0.0"
25
- s.add_dependency "rest-client", ">= 2.0.0"
26
- else
27
- s.add_dependency "rest-client"
28
- end
29
-
30
- if RUBY_VERSION >= "3.0.0"
31
- s.add_development_dependency "rexml"
32
- end
33
-
34
- s.add_development_dependency "actionpack"
35
- s.add_development_dependency "nokogiri"
36
-
37
- if RUBY_VERSION >= "2.2.0"
38
- s.add_development_dependency "rake", ">= 13.0.1"
39
- else
40
- s.add_development_dependency "rake", "<= 12.2.1"
41
- end
42
- if RUBY_VERSION >= "3.0.0"
43
- s.add_development_dependency "sqlite3"
44
- else
45
- s.add_development_dependency "sqlite3", "< 1.6.0"
46
- end
47
-
48
- s.add_development_dependency "rspec", '>=3.5'
49
- s.add_development_dependency "rspec-retry"
50
-
51
- if RUBY_VERSION >= "3.0.0"
52
- s.add_development_dependency "rails", "~> 6.0.3"
53
- elsif RUBY_VERSION >= "2.2.2"
54
- s.add_development_dependency "rails", "~> 5.2"
55
- end
56
-
57
- s.add_development_dependency "railties", "<= 4.2.7" if RUBY_VERSION <= "1.9.3"
58
- s.add_development_dependency "rspec-rails"
59
-
60
- s.add_development_dependency "rubyzip"
61
-
62
- if RUBY_VERSION <= "2.4.0"
63
- s.add_development_dependency "simplecov", "<= 0.17.1" # support testing Ruby 1.9
64
- s.add_development_dependency 'loofah', '~>2.19.1'
65
- s.add_development_dependency "rails-html-sanitizer", "<1.5.0"
66
- else
67
- s.add_development_dependency "simplecov", "> 0.18.0"
68
- end
21
+ s.required_ruby_version = '~> 3'
22
+
23
+ s.add_dependency "faraday", ">= 2.0.1", "< 3.0.0"
24
+ s.add_dependency "faraday-multipart", "~> 1.0", ">= 1.0.4"
25
+
26
+ s.add_development_dependency 'faraday-follow_redirects', '~> 0.3.0'
27
+ s.add_development_dependency "rails", ">= 6.1.7", "< 8.0.0"
28
+ s.add_development_dependency "rexml", ">= 3.2.5", "< 4.0.0"
29
+ s.add_development_dependency "actionpack", ">= 6.1.7", "< 8.0.0"
30
+ s.add_development_dependency "nokogiri", ">= 1.12.5", "< 2.0.0"
31
+ s.add_development_dependency "rake", ">= 13.0.6", "< 14.0.0"
32
+ s.add_development_dependency "sqlite3", ">= 1.4.2", "< 2.0.0"
33
+ s.add_development_dependency "rspec", ">= 3.11.2", "< 4.0.0"
34
+ s.add_development_dependency "rspec-retry", ">= 0.6.2", "< 1.0.0"
35
+ s.add_development_dependency "railties", ">= 6.0.4", "< 8.0.0"
36
+ s.add_development_dependency "rspec-rails", ">= 6.0.4", "< 7.0.0"
37
+ s.add_development_dependency "rubyzip", ">= 2.3.0", "< 3.0.0"
38
+ s.add_development_dependency "simplecov", ">= 0.21.2", "< 1.0.0"
69
39
  end
@@ -39,10 +39,12 @@ module ActiveStorage
39
39
  begin
40
40
  extra_headers = checksum.nil? ? {} : {Headers::CONTENT_MD5 => checksum}
41
41
  options = @options.merge(options)
42
+ resource_type = resource_type(io, key)
43
+ options[:format] = ext_for_file(key) if resource_type == "raw"
42
44
  Cloudinary::Uploader.upload_large(
43
45
  io,
44
46
  public_id: public_id_internal(key),
45
- resource_type: resource_type(io, key),
47
+ resource_type: resource_type,
46
48
  context: {active_storage_key: key, checksum: checksum},
47
49
  extra_headers: extra_headers,
48
50
  **options
@@ -149,7 +151,7 @@ module ActiveStorage
149
151
 
150
152
  # Return the partial content in the byte +range+ of the file at the +key+.
151
153
  def download_chunk(key, range)
152
- url = Cloudinary::Utils.unsigned_download_url(public_id(key), resource_type: resource_type(nil, key))
154
+ url = Cloudinary::Utils.cloudinary_url(public_id(key), resource_type: resource_type(nil, key))
153
155
  uri = URI(url)
154
156
  instrument :download, key: key do
155
157
  req = Net::HTTP::Get.new(uri)
@@ -127,18 +127,30 @@ class Cloudinary::AccountApi
127
127
  call_account_api(:get, ['users', user_id], {}, options.merge(content_type: :json))
128
128
  end
129
129
 
130
- # Lists users in the account.
131
- # @param [Boolean] pending Limit results to pending users (true), users that are not pending (false), or all users (nil, the default)
132
- # @param [Array<String>] user_ids A list of up to 100 user IDs. When provided, other parameters are ignored.
133
- # @param [String] prefix Returns users where the name or email address begins with the specified case-insensitive string.
134
- # @param [String] sub_account_id Only returns users who have access to the specified account.
135
- # @param [Object] options additional options
130
+ # Get a list of the users according to filters.
131
+ #
132
+ # @param [Boolean] pending Optional. Limit results to pending users (true), users that are not pending (false), or all users (null)
133
+ # @param [Array<String>] user_ids Optional. List of user IDs. Up to 100
134
+ # @param [String] prefix Optional. Search by prefix of the user's name or email. Case-insensitive
135
+ # @param [String] sub_account_id Optional. Return only users who have access to the given sub-account
136
+ # @param [Object] options Generic advanced options map, see online documentation.
137
+ # @option options [Boolean] :last_login Optional. Return only users that last logged in in the specified range of dates (true),
138
+ # users that didn't last logged in in that range (false), or all users (null).
139
+ # @option options [Date] :from Optional. Last login start date.
140
+ # @option options [Date] :to Optional. Last login end date.
141
+ #
142
+ # @return [Cloudinary::Api::Response] the users' details.
143
+ #
144
+ # @raise [Cloudinary::Api::Error] If the request fails.
136
145
  def self.users(pending = nil, user_ids = [], prefix = nil, sub_account_id = nil, options = {})
137
146
  params = {
138
147
  ids: user_ids,
139
148
  prefix: prefix,
140
149
  sub_account_id: sub_account_id,
141
- pending: pending
150
+ pending: pending,
151
+ last_login: options[:last_login].to_s,
152
+ from: Cloudinary::Utils.to_usage_api_date_format(options[:from]),
153
+ to: Cloudinary::Utils.to_usage_api_date_format(options[:to])
142
154
  }
143
155
 
144
156
  call_account_api(:get, 'users', params, options.merge(content_type: :json))
@@ -252,12 +264,13 @@ class Cloudinary::AccountApi
252
264
  account_id = options[:account_id] || Cloudinary.account_config.account_id || raise('Must supply account_id')
253
265
  api_key = options[:provisioning_api_key] || Cloudinary.account_config.provisioning_api_key || raise('Must supply provisioning api_key')
254
266
  api_secret = options[:provisioning_api_secret] || Cloudinary.account_config.provisioning_api_secret || raise('Must supply provisioning api_secret')
267
+ api_version = options[:api_version] || Cloudinary.config.api_version || 'v1_1'
255
268
 
256
269
  params.reject! { |_, v| v.nil? }
257
270
  auth = { :key => api_key, :secret => api_secret }
258
271
 
259
272
  call_cloudinary_api(method, uri, auth, params, options) do |cloudinary, inner_uri|
260
- [cloudinary, 'v1_1', 'provisioning', 'accounts', account_id, inner_uri]
273
+ [cloudinary, api_version, 'provisioning', 'accounts', account_id, inner_uri]
261
274
  end
262
275
  end
263
276
 
@@ -0,0 +1,157 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cloudinary
4
+ module Analytics
5
+ extend self
6
+
7
+ QUERY_KEY = '_a'
8
+ ALGO_VERSION = 'B' # The version of the algorithm
9
+ SDK_CODE = 'C' # Cloudinary Ruby SDK
10
+
11
+ @product = 'A' # Official SDK. Set to 'B' for integrations.
12
+ @sdk_code = SDK_CODE
13
+ @sdk_version = Cloudinary::VERSION
14
+ @tech_version = "#{RUBY_VERSION[/\d+\.\d+/]}"
15
+
16
+ CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
17
+ BINARY_PAD_SIZE = 6
18
+
19
+ @char_codes = nil
20
+ @signature = nil
21
+
22
+ # Gets the SDK analytics signature query parameter.
23
+ #
24
+ # @return [String] The SDK signature query parameter.
25
+ def sdk_analytics_query_param
26
+ "#{QUERY_KEY}=#{self.sdk_analytics_signature}"
27
+ end
28
+
29
+ # Gets the SDK signature by encoding the SDK version and tech version.
30
+ #
31
+ # @return [String] The SDK signature.
32
+ def sdk_analytics_signature
33
+ return @signature unless @signature.nil?
34
+
35
+ begin
36
+ @signature = ALGO_VERSION + @product + @sdk_code + encode_version(@sdk_version) + encode_version(@tech_version)
37
+ rescue RangeError
38
+ @signature = 'E'
39
+ end
40
+
41
+ @signature
42
+ end
43
+
44
+ # Sets the product code.
45
+ #
46
+ # Used for integrations.
47
+ #
48
+ # @param [String] product The product code to set. 'A' is for the official SDK. 'B' for integrations.
49
+ #
50
+ # @return [void]
51
+ #
52
+ # @internal
53
+ def product(product)
54
+ @product = product
55
+ end
56
+
57
+ # Sets the SDK code.
58
+ #
59
+ # Used for integrations.
60
+ #
61
+ # @param [String] sdk_code The SDK code to set.
62
+ #
63
+ # @return [void]
64
+ #
65
+ # @internal
66
+ def sdk_code(sdk_code)
67
+ @sdk_code = sdk_code
68
+ end
69
+
70
+ # Sets the SDK version.
71
+ #
72
+ # Used for integrations.
73
+ #
74
+ # @param [String] sdk_version The SDK version to set (MAJOR.MINOR.PATCH), for example: "1.0.0".
75
+ #
76
+ # @return [void]
77
+ #
78
+ # @internal
79
+ def sdk_version(sdk_version)
80
+ @sdk_version = sdk_version
81
+ end
82
+
83
+ # Sets the tech version.
84
+ #
85
+ # Used for integrations.
86
+ #
87
+ # @param [String] tech_version The tech version to set (MAJOR.MINOR), for example: "1.0".
88
+ #
89
+ # @return [void]
90
+ #
91
+ # @internal
92
+ def tech_version(tech_version)
93
+ @tech_version = tech_version.split('.').first(2).join('.')
94
+ end
95
+
96
+ # Encodes a semVer-like version string.
97
+ #
98
+ # Example:
99
+ # input: '1.24.0'
100
+ # explode: ['1','24','0']
101
+ # pad: ['01','24','00']
102
+ # reverse: ['00', '24', '01']
103
+ # implode: '002401'
104
+ # int: 2401
105
+ # binary: '100101100001'
106
+ # padded: '000000100101100001'
107
+ # str_split: ['000000', '100101', '100001']
108
+ # getKey: ['A', 'l', 'h']
109
+ # implode: 'Alh'
110
+ #
111
+ # @param [String] version Can be either x.y.z or x.y
112
+ #
113
+ # @return [String] A string built from 3 characters of the base64 table
114
+ #
115
+ # @raise [RangeError] when version is larger than 43.21.26
116
+ def encode_version(version)
117
+ parts = version.split('.')
118
+
119
+ padded_parts = parts.map { |part| part.rjust(2, '0') }
120
+ number = padded_parts.reverse.join.to_i
121
+ padded_binary = int_to_padded_bin(number, parts.length * BINARY_PAD_SIZE)
122
+
123
+ raise RangeError, 'Version must be smaller than 43.21.26' if padded_binary.length % BINARY_PAD_SIZE != 0
124
+
125
+ encoded_chars = padded_binary.chars.each_slice(BINARY_PAD_SIZE).map { |slice| get_key(slice.join) }
126
+
127
+ encoded_chars.join
128
+ end
129
+
130
+ # Gets the key for binary value.
131
+ #
132
+ # @param [String] binary_value The value.
133
+ #
134
+ # @return [Array, Object] The key for the binary value.
135
+ def get_key(binary_value)
136
+ @char_codes ||= initialize_char_codes
137
+
138
+ @char_codes[binary_value] || ''
139
+ end
140
+
141
+ def initialize_char_codes
142
+ char_codes = {}
143
+ CHARS.chars.each_with_index { |char, idx| char_codes[int_to_padded_bin(idx, BINARY_PAD_SIZE)] = char }
144
+ char_codes
145
+ end
146
+
147
+ # Converts integer to left padded binary string.
148
+ #
149
+ # @param [Integer] integer The input.
150
+ # @param [Integer] pad_num The num of padding chars.
151
+ #
152
+ # @return [String] The padded binary string.
153
+ def int_to_padded_bin(integer, pad_num)
154
+ integer.to_s(2).rjust(pad_num, '0')
155
+ end
156
+ end
157
+ end
@@ -649,7 +649,7 @@ class Cloudinary::Api
649
649
  #
650
650
  # @see https://cloudinary.com/documentation/admin_api#update_an_upload_preset
651
651
  def self.update_upload_preset(name, options={})
652
- params = Cloudinary::Uploader.build_upload_params(options)
652
+ params = Cloudinary::Uploader.build_upload_params(options, true)
653
653
  call_api(:put, "upload_presets/#{name}", params.merge(only(options, :unsigned, :disallow_public_id, :live)), options)
654
654
  end
655
655
 
@@ -664,7 +664,7 @@ class Cloudinary::Api
664
664
  #
665
665
  # @see https://cloudinary.com/documentation/admin_api#create_an_upload_preset
666
666
  def self.create_upload_preset(options={})
667
- params = Cloudinary::Uploader.build_upload_params(options)
667
+ params = Cloudinary::Uploader.build_upload_params(options, true)
668
668
  call_api(:post, "upload_presets", params.merge(only(options, :name, :unsigned, :disallow_public_id, :live)), options)
669
669
  end
670
670
 
@@ -1222,6 +1222,25 @@ class Cloudinary::Api
1222
1222
  call_metadata_rules_api(:delete, uri, {}, options)
1223
1223
  end
1224
1224
 
1225
+ # Analyzes an asset with the requested analysis type.
1226
+ #
1227
+ # @param [Object] input_type The type of input for the asset to analyze ('uri').
1228
+ # @param [Object] analysis_type The type of analysis to run ('google_tagging', 'captioning', 'fashion').
1229
+ # @param [Hash] options The optional parameters.
1230
+ #
1231
+ # @return [Cloudinary::Api::Response]
1232
+ #
1233
+ # @raise [Cloudinary::Api::Error]
1234
+ def self.analyze(input_type, analysis_type, options = {})
1235
+ api_uri = ["analysis", "analyze", input_type]
1236
+ params = only(options, :uri, :parameters)
1237
+ params["analysis_type"] = analysis_type
1238
+
1239
+ options[:api_version] = 'v2'
1240
+
1241
+ call_api(:post, api_uri, params, options)
1242
+ end
1243
+
1225
1244
  protected
1226
1245
 
1227
1246
  # Execute a call api for input params.
@@ -1236,13 +1255,14 @@ class Cloudinary::Api
1236
1255
  api_key = options[:api_key] || Cloudinary.config.api_key
1237
1256
  api_secret = options[:api_secret] || Cloudinary.config.api_secret
1238
1257
  oauth_token = options[:oauth_token] || Cloudinary.config.oauth_token
1258
+ api_version = options[:api_version] || Cloudinary.config.api_version || 'v1_1'
1239
1259
 
1240
1260
  validate_authorization(api_key, api_secret, oauth_token)
1241
1261
 
1242
1262
  auth = { :key => api_key, :secret => api_secret, :oauth_token => oauth_token }
1243
1263
 
1244
1264
  call_cloudinary_api(method, uri, auth, params, options) do |cloudinary, inner_uri|
1245
- [cloudinary, 'v1_1', cloud_name, inner_uri]
1265
+ [cloudinary, api_version, cloud_name, inner_uri]
1246
1266
  end
1247
1267
  end
1248
1268
 
@@ -1254,7 +1274,7 @@ class Cloudinary::Api
1254
1274
  return Cloudinary::Utils.json_decode(response.body)
1255
1275
  rescue => e
1256
1276
  # Error is parsing json
1257
- raise GeneralError.new("Error parsing server response (#{response.code}) - #{response.body}. Got - #{e}")
1277
+ raise GeneralError.new("Error parsing server response (#{response.status}) - #{response.body}. Got - #{e}")
1258
1278
  end
1259
1279
 
1260
1280
  # Protected function that assists with performing an API call to the metadata_fields part of the Admin API.
@@ -1,11 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'openssl'
4
- if RUBY_VERSION > "2"
5
- require "ostruct"
6
- else
7
- require "cloudinary/ostruct2"
8
- end
4
+ require "ostruct"
9
5
 
10
6
 
11
7
  module Cloudinary
@@ -1,7 +1,8 @@
1
- require "rest_client"
1
+ require "faraday"
2
2
  require "json"
3
3
 
4
4
  module Cloudinary::BaseApi
5
+ @adapter = nil
5
6
  class Error < CloudinaryException; end
6
7
  class NotFound < Error; end
7
8
  class NotAllowed < Error; end
@@ -15,17 +16,19 @@ module Cloudinary::BaseApi
15
16
  attr_reader :rate_limit_reset_at, :rate_limit_remaining, :rate_limit_allowed
16
17
 
17
18
  def initialize(response=nil)
18
- if response
19
- # This sets the instantiated self as the response Hash
20
- update Cloudinary::Api.parse_json_response response
19
+ unless response
20
+ return
21
+ end
21
22
 
22
- # According to RFC 2616, header names are case-insensitive.
23
- lc_headers = response.headers.transform_keys(&:downcase)
23
+ # This sets the instantiated self as the response Hash
24
+ update Cloudinary::Api.parse_json_response response
24
25
 
25
- @rate_limit_allowed = lc_headers[:x_featureratelimit_limit].to_i if lc_headers[:x_featureratelimit_limit]
26
- @rate_limit_reset_at = Time.parse(lc_headers[:x_featureratelimit_reset]) if lc_headers[:x_featureratelimit_reset]
27
- @rate_limit_remaining = lc_headers[:x_featureratelimit_remaining].to_i if lc_headers[:x_featureratelimit_remaining]
28
- end
26
+ # According to RFC 2616, header names are case-insensitive.
27
+ lc_headers = response.headers.transform_keys(&:downcase)
28
+
29
+ @rate_limit_allowed = lc_headers["x-featureratelimit-limit"].to_i if lc_headers["x-featureratelimit-limit"]
30
+ @rate_limit_reset_at = Time.parse(lc_headers["x-featureratelimit-reset"]) if lc_headers["x-featureratelimit-reset"]
31
+ @rate_limit_remaining = lc_headers["x-featureratelimit-remaining"].to_i if lc_headers["x-featureratelimit-remaining"]
29
32
  end
30
33
  end
31
34
 
@@ -36,28 +39,30 @@ module Cloudinary::BaseApi
36
39
  end
37
40
 
38
41
  def call_json_api(method, api_url, payload, timeout, headers, proxy = nil, user = nil, password = nil)
39
- RestClient::Request.execute(method: method,
40
- url: api_url,
41
- payload: payload,
42
- timeout: timeout,
43
- headers: headers,
44
- proxy: proxy,
45
- user: user,
46
- password: password) do |response|
47
- return Response.new(response) if response.code == 200
48
- exception_class = case response.code
49
- when 400 then BadRequest
50
- when 401 then AuthorizationRequired
51
- when 403 then NotAllowed
52
- when 404 then NotFound
53
- when 409 then AlreadyExists
54
- when 420 then RateLimited
55
- when 500 then GeneralError
56
- else raise GeneralError.new("Server returned unexpected status code - #{response.code} - #{response.body}")
57
- end
58
- json = Cloudinary::Api.parse_json_response(response)
59
- raise exception_class.new(json["error"]["message"])
42
+ conn = Faraday.new(url: api_url) do |faraday|
43
+ faraday.proxy = proxy if proxy
44
+ faraday.request :json
45
+ faraday.adapter @adapter || Faraday.default_adapter
60
46
  end
47
+
48
+ response = conn.run_request(method.downcase.to_sym, nil, payload, headers) do |req|
49
+ req.options.timeout = timeout if timeout
50
+ req.basic_auth(user, password) if user && password
51
+ end
52
+
53
+ return Response.new(response) if response.status == 200
54
+ exception_class = case response.status
55
+ when 400 then BadRequest
56
+ when 401 then AuthorizationRequired
57
+ when 403 then NotAllowed
58
+ when 404 then NotFound
59
+ when 409 then AlreadyExists
60
+ when 420 then RateLimited
61
+ when 500 then GeneralError
62
+ else raise GeneralError.new("Server returned unexpected status code - #{response.status} - #{response.body}")
63
+ end
64
+ json = Cloudinary::Api.parse_json_response(response)
65
+ raise exception_class.new(json["error"]["message"])
61
66
  end
62
67
 
63
68
  private
@@ -36,7 +36,8 @@ class Cloudinary::CarrierWave::Storage < ::CarrierWave::Storage::Abstract
36
36
  params[:type]=uploader.class.storage_type
37
37
 
38
38
  params[:resource_type] ||= :auto
39
- uploader.metadata = Cloudinary::Uploader.upload(data, params)
39
+ upload_method = uploader.upload_chunked? ? "upload_large" : "upload"
40
+ uploader.metadata = Cloudinary::Uploader.send(upload_method, data, params)
40
41
  if uploader.metadata["error"]
41
42
  raise Cloudinary::CarrierWave::UploadError.new(uploader.metadata["error"]["message"], uploader.metadata["error"]["http_code"])
42
43
  end
@@ -192,11 +192,6 @@ module Cloudinary::CarrierWave
192
192
 
193
193
  end
194
194
 
195
- # @deprecated
196
- def self.split_format(identifier)
197
- return Cloudinary::PreloadedFile.split_format(identifier)
198
- end
199
-
200
195
  def default_format
201
196
  "png"
202
197
  end
@@ -286,13 +286,6 @@ module CloudinaryHelper
286
286
  Cloudinary::Utils.private_download_url(public_id, format, options)
287
287
  end
288
288
 
289
- # Helper method that uses the deprecated ZIP download API.
290
- # Replaced by cl_download_zip_url that uses the more advanced and robust archive generation and download API
291
- # @deprecated
292
- def cl_zip_download_url(tag, options = {})
293
- Cloudinary::Utils.zip_download_url(tag, options)
294
- end
295
-
296
289
  # @see {Cloudinary::Utils.download_archive_url}
297
290
  def cl_download_archive_url(options = {})
298
291
  Cloudinary::Utils.download_archive_url(options)
@@ -304,13 +297,13 @@ module CloudinaryHelper
304
297
  end
305
298
 
306
299
  def cl_signed_download_url(public_id, options = {})
307
- Cloudinary::Utils.signed_download_url(public_id, options)
300
+ Cloudinary::Utils.cloudinary_url(public_id, options)
308
301
  end
309
302
 
310
303
  def self.included(base)
311
304
  ActionView::Helpers::FormBuilder.send(:include, Cloudinary::FormBuilder)
312
305
  base.class_eval do
313
- if !method_defined?(:image_tag)
306
+ unless method_defined?(:image_tag)
314
307
  include ActionView::Helpers::AssetTagHelper
315
308
  end
316
309
  alias_method :image_tag_without_cloudinary, :image_tag unless public_method_defined? :image_tag_without_cloudinary
@@ -325,7 +318,6 @@ module CloudinaryHelper
325
318
  private
326
319
 
327
320
  def cloudinary_url_internal(source, options = {})
328
- options[:ssl_detected] = request.ssl? if defined?(request) && request && request.respond_to?(:ssl?)
329
321
  if defined?(CarrierWave::Uploader::Base) && source.is_a?(CarrierWave::Uploader::Base)
330
322
  if source.version_name.present?
331
323
  options[:transformation] = Cloudinary::Utils.build_array(source.transformation) + Cloudinary::Utils.build_array(options[:transformation])