cloudinary 1.28.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +8 -14
- data/CHANGELOG.md +51 -0
- data/README.md +7 -5
- data/cloudinary.gemspec +21 -51
- data/lib/active_storage/service/cloudinary_service.rb +6 -2
- data/lib/cloudinary/account_api.rb +76 -25
- data/lib/cloudinary/analytics.rb +157 -0
- data/lib/cloudinary/api.rb +63 -36
- data/lib/cloudinary/auth_token.rb +1 -5
- data/lib/cloudinary/base_api.rb +36 -31
- data/lib/cloudinary/carrier_wave/storage.rb +2 -1
- data/lib/cloudinary/carrier_wave.rb +0 -5
- data/lib/cloudinary/helper.rb +2 -10
- data/lib/cloudinary/migrator.rb +70 -71
- data/lib/cloudinary/railtie.rb +3 -1
- data/lib/cloudinary/search.rb +18 -3
- data/lib/cloudinary/uploader.rb +70 -90
- data/lib/cloudinary/utils.rb +39 -55
- data/lib/cloudinary/version.rb +1 -1
- data/lib/cloudinary/video_helper.rb +3 -2
- data/lib/cloudinary.rb +3 -9
- data/lib/tasks/cloudinary/fetch_assets.rake +9 -3
- data/vendor/assets/javascripts/cloudinary/jquery.cloudinary.js +3 -3
- metadata +164 -38
- data/lib/cloudinary/ostruct2.rb +0 -284
data/lib/cloudinary/api.rb
CHANGED
@@ -68,7 +68,7 @@ class Cloudinary::Api
|
|
68
68
|
type = options[:type]
|
69
69
|
uri = "resources/#{resource_type}"
|
70
70
|
uri += "/#{type}" unless type.blank?
|
71
|
-
call_api(:get, uri, only(options, :
|
71
|
+
call_api(:get, uri, list_resources_params(options).merge(only(options, :prefix, :start_at)), options)
|
72
72
|
end
|
73
73
|
|
74
74
|
# Lists assets with the specified tag.
|
@@ -87,7 +87,7 @@ class Cloudinary::Api
|
|
87
87
|
def self.resources_by_tag(tag, options={})
|
88
88
|
resource_type = options[:resource_type] || "image"
|
89
89
|
uri = "resources/#{resource_type}/tags/#{tag}"
|
90
|
-
call_api(:get, uri,
|
90
|
+
call_api(:get, uri, list_resources_params(options), options)
|
91
91
|
end
|
92
92
|
|
93
93
|
# Lists assets currently in the specified moderation queue and status.
|
@@ -107,7 +107,7 @@ class Cloudinary::Api
|
|
107
107
|
def self.resources_by_moderation(kind, status, options={})
|
108
108
|
resource_type = options[:resource_type] || "image"
|
109
109
|
uri = "resources/#{resource_type}/moderations/#{kind}/#{status}"
|
110
|
-
call_api(:get, uri,
|
110
|
+
call_api(:get, uri, list_resources_params(options), options)
|
111
111
|
end
|
112
112
|
|
113
113
|
# Lists assets with the specified contextual metadata.
|
@@ -129,30 +129,9 @@ class Cloudinary::Api
|
|
129
129
|
def self.resources_by_context(key, value=nil, options={})
|
130
130
|
resource_type = options[:resource_type] || "image"
|
131
131
|
uri = "resources/#{resource_type}/context"
|
132
|
-
|
133
|
-
params[:key] = key
|
134
|
-
params[:value] = value
|
135
|
-
call_api(:get, uri, params, options)
|
132
|
+
call_api(:get, uri, list_resources_params(options, :key => key, :value => value), options)
|
136
133
|
end
|
137
134
|
|
138
|
-
# Returns the details of the specified asset and all its derived assets by asset id.
|
139
|
-
#
|
140
|
-
# Note that if you only need details about the original asset,
|
141
|
-
# you can also use the Uploader::upload or Uploader::explicit methods, which return the same information and
|
142
|
-
# are not rate limited.
|
143
|
-
#
|
144
|
-
# @param [String] asset_id The Asset ID of the asset.
|
145
|
-
# @param [Hash] options The optional parameters. See the <a href=https://cloudinary.com/documentation/admin_api#get_the_details_of_a_single_resource target="_blank"> Admin API</a> documentation.
|
146
|
-
#
|
147
|
-
# @return [Cloudinary::Api::Response]
|
148
|
-
#
|
149
|
-
# @see https://cloudinary.com/documentation/admin_api#get_the_details_of_a_single_resource
|
150
|
-
def self.resource_by_asset_id(asset_id, options={})
|
151
|
-
uri = "resources/#{asset_id}"
|
152
|
-
params = prepare_resource_details_params(options)
|
153
|
-
call_api(:get, uri, params, options)
|
154
|
-
end
|
155
|
-
|
156
135
|
# Lists assets with the specified public IDs.
|
157
136
|
#
|
158
137
|
# @param [String|Array] public_ids The requested public_ids (up to 100).
|
@@ -168,7 +147,7 @@ class Cloudinary::Api
|
|
168
147
|
resource_type = options[:resource_type] || "image"
|
169
148
|
type = options[:type] || "upload"
|
170
149
|
uri = "resources/#{resource_type}/#{type}"
|
171
|
-
call_api(:get, uri,
|
150
|
+
call_api(:get, uri, resources_params(options, :public_ids => public_ids), options)
|
172
151
|
end
|
173
152
|
|
174
153
|
# Lists assets with the specified asset IDs.
|
@@ -184,9 +163,7 @@ class Cloudinary::Api
|
|
184
163
|
# @see https://cloudinary.com/documentation/admin_api#get_resources
|
185
164
|
def self.resources_by_asset_ids(asset_ids, options={})
|
186
165
|
uri = "resources/by_asset_ids"
|
187
|
-
|
188
|
-
params[:asset_ids] = asset_ids
|
189
|
-
call_api(:get, uri, params, options)
|
166
|
+
call_api(:get, uri, resources_params(options, :asset_ids => asset_ids), options)
|
190
167
|
end
|
191
168
|
|
192
169
|
# Returns all assets stored directly in a specified asset folder, regardless of the public ID paths of those assets.
|
@@ -202,9 +179,7 @@ class Cloudinary::Api
|
|
202
179
|
# @see https://cloudinary.com/documentation/dynamic_folders#new_admin_api_endpoints
|
203
180
|
def self.resources_by_asset_folder(asset_folder, options={})
|
204
181
|
uri = "resources/by_asset_folder"
|
205
|
-
|
206
|
-
params[:asset_folder] = asset_folder
|
207
|
-
call_api(:get, uri, params, options)
|
182
|
+
call_api(:get, uri, list_resources_params(options, :asset_folder => asset_folder), options)
|
208
183
|
end
|
209
184
|
|
210
185
|
# Find images based on their visual content.
|
@@ -243,6 +218,23 @@ class Cloudinary::Api
|
|
243
218
|
call_api(:get, uri, prepare_resource_details_params(options), options)
|
244
219
|
end
|
245
220
|
|
221
|
+
# Returns the details of the specified asset and all its derived assets by asset id.
|
222
|
+
#
|
223
|
+
# Note that if you only need details about the original asset,
|
224
|
+
# you can also use the Uploader::upload or Uploader::explicit methods, which return the same information and
|
225
|
+
# are not rate limited.
|
226
|
+
#
|
227
|
+
# @param [String] asset_id The Asset ID of the asset.
|
228
|
+
# @param [Hash] options The optional parameters. See the <a href=https://cloudinary.com/documentation/admin_api#get_the_details_of_a_single_resource target="_blank"> Admin API</a> documentation.
|
229
|
+
#
|
230
|
+
# @return [Cloudinary::Api::Response]
|
231
|
+
#
|
232
|
+
# @see https://cloudinary.com/documentation/admin_api#get_the_details_of_a_single_resource
|
233
|
+
def self.resource_by_asset_id(asset_id, options={})
|
234
|
+
uri = "resources/#{asset_id}"
|
235
|
+
call_api(:get, uri, prepare_resource_details_params(options), options)
|
236
|
+
end
|
237
|
+
|
246
238
|
# Reverts to the latest backed up version of the specified deleted assets.
|
247
239
|
#
|
248
240
|
# @param [String|Array] public_ids The public IDs of the backed up assets to restore. They can be existing or
|
@@ -657,7 +649,7 @@ class Cloudinary::Api
|
|
657
649
|
#
|
658
650
|
# @see https://cloudinary.com/documentation/admin_api#update_an_upload_preset
|
659
651
|
def self.update_upload_preset(name, options={})
|
660
|
-
params = Cloudinary::Uploader.build_upload_params(options)
|
652
|
+
params = Cloudinary::Uploader.build_upload_params(options, true)
|
661
653
|
call_api(:put, "upload_presets/#{name}", params.merge(only(options, :unsigned, :disallow_public_id, :live)), options)
|
662
654
|
end
|
663
655
|
|
@@ -672,7 +664,7 @@ class Cloudinary::Api
|
|
672
664
|
#
|
673
665
|
# @see https://cloudinary.com/documentation/admin_api#create_an_upload_preset
|
674
666
|
def self.create_upload_preset(options={})
|
675
|
-
params = Cloudinary::Uploader.build_upload_params(options)
|
667
|
+
params = Cloudinary::Uploader.build_upload_params(options, true)
|
676
668
|
call_api(:post, "upload_presets", params.merge(only(options, :name, :unsigned, :disallow_public_id, :live)), options)
|
677
669
|
end
|
678
670
|
|
@@ -1230,6 +1222,25 @@ class Cloudinary::Api
|
|
1230
1222
|
call_metadata_rules_api(:delete, uri, {}, options)
|
1231
1223
|
end
|
1232
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
|
+
|
1233
1244
|
protected
|
1234
1245
|
|
1235
1246
|
# Execute a call api for input params.
|
@@ -1244,13 +1255,14 @@ class Cloudinary::Api
|
|
1244
1255
|
api_key = options[:api_key] || Cloudinary.config.api_key
|
1245
1256
|
api_secret = options[:api_secret] || Cloudinary.config.api_secret
|
1246
1257
|
oauth_token = options[:oauth_token] || Cloudinary.config.oauth_token
|
1258
|
+
api_version = options[:api_version] || Cloudinary.config.api_version || 'v1_1'
|
1247
1259
|
|
1248
1260
|
validate_authorization(api_key, api_secret, oauth_token)
|
1249
1261
|
|
1250
1262
|
auth = { :key => api_key, :secret => api_secret, :oauth_token => oauth_token }
|
1251
1263
|
|
1252
1264
|
call_cloudinary_api(method, uri, auth, params, options) do |cloudinary, inner_uri|
|
1253
|
-
[cloudinary,
|
1265
|
+
[cloudinary, api_version, cloud_name, inner_uri]
|
1254
1266
|
end
|
1255
1267
|
end
|
1256
1268
|
|
@@ -1262,7 +1274,7 @@ class Cloudinary::Api
|
|
1262
1274
|
return Cloudinary::Utils.json_decode(response.body)
|
1263
1275
|
rescue => e
|
1264
1276
|
# Error is parsing json
|
1265
|
-
raise GeneralError.new("Error parsing server response (#{response.
|
1277
|
+
raise GeneralError.new("Error parsing server response (#{response.status}) - #{response.body}. Got - #{e}")
|
1266
1278
|
end
|
1267
1279
|
|
1268
1280
|
# Protected function that assists with performing an API call to the metadata_fields part of the Admin API.
|
@@ -1399,4 +1411,19 @@ class Cloudinary::Api
|
|
1399
1411
|
params[by_key] = value
|
1400
1412
|
call_api("post", "resources/#{resource_type}/#{type}/update_access_mode", params, options)
|
1401
1413
|
end
|
1414
|
+
|
1415
|
+
private
|
1416
|
+
|
1417
|
+
RESOURCES_PARAMS = [:tags, :context, :metadata, :moderations, :fields].freeze
|
1418
|
+
LIST_RESOURCES_PARAMS = [:next_cursor, :max_results, :direction].freeze
|
1419
|
+
|
1420
|
+
def self.resources_params(options, params = {})
|
1421
|
+
params.merge!(only(options, *RESOURCES_PARAMS))
|
1422
|
+
params[:fields] = Cloudinary::Utils.build_array(options[:fields]).join(",") unless params[:fields].nil?
|
1423
|
+
params
|
1424
|
+
end
|
1425
|
+
|
1426
|
+
def self.list_resources_params(options, params = {})
|
1427
|
+
params.merge(resources_params(options)).merge!(only(options, *LIST_RESOURCES_PARAMS))
|
1428
|
+
end
|
1402
1429
|
end
|
data/lib/cloudinary/base_api.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
-
require "
|
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
|
-
|
19
|
-
|
20
|
-
|
19
|
+
unless response
|
20
|
+
return
|
21
|
+
end
|
21
22
|
|
22
|
-
|
23
|
-
|
23
|
+
# This sets the instantiated self as the response Hash
|
24
|
+
update Cloudinary::Api.parse_json_response response
|
24
25
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
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
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
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.
|
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
|
data/lib/cloudinary/helper.rb
CHANGED
@@ -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.
|
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
|
-
|
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])
|