cloudinary 1.27.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +8 -14
- data/CHANGELOG.md +126 -0
- data/README.md +7 -5
- data/cloudinary.gemspec +25 -50
- data/lib/active_storage/service/cloudinary_service.rb +63 -8
- data/lib/cloudinary/account_api.rb +94 -25
- data/lib/cloudinary/analytics.rb +157 -0
- data/lib/cloudinary/api.rb +110 -44
- data/lib/cloudinary/auth_token.rb +1 -5
- data/lib/cloudinary/base_api.rb +36 -31
- data/lib/cloudinary/carrier_wave/storage.rb +3 -9
- data/lib/cloudinary/carrier_wave.rb +0 -5
- data/lib/cloudinary/helper.rb +3 -11
- 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 +72 -104
- data/lib/cloudinary/utils.rb +53 -48
- 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 +179 -38
- data/lib/cloudinary/ostruct2.rb +0 -284
@@ -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
|
data/lib/cloudinary/api.rb
CHANGED
@@ -14,6 +14,22 @@ class Cloudinary::Api
|
|
14
14
|
call_api(:get, "ping", {}, options)
|
15
15
|
end
|
16
16
|
|
17
|
+
# Retrieves account configuration details.
|
18
|
+
#
|
19
|
+
# @param [Hash] options The optional parameters.
|
20
|
+
#
|
21
|
+
# @return [Cloudinary::Api::Response]
|
22
|
+
#
|
23
|
+
# @raise [Cloudinary::Api::Error]
|
24
|
+
#
|
25
|
+
# @see https://cloudinary.com/documentation/admin_api#config
|
26
|
+
def self.config(options={})
|
27
|
+
uri = "config"
|
28
|
+
params = only(options, :settings)
|
29
|
+
|
30
|
+
call_api(:get, uri, params, options)
|
31
|
+
end
|
32
|
+
|
17
33
|
# Gets cloud usage details.
|
18
34
|
#
|
19
35
|
# Returns a report detailing your current Cloudinary cloud usage details, including
|
@@ -68,7 +84,7 @@ class Cloudinary::Api
|
|
68
84
|
type = options[:type]
|
69
85
|
uri = "resources/#{resource_type}"
|
70
86
|
uri += "/#{type}" unless type.blank?
|
71
|
-
call_api(:get, uri, only(options, :
|
87
|
+
call_api(:get, uri, list_resources_params(options).merge(only(options, :prefix, :start_at)), options)
|
72
88
|
end
|
73
89
|
|
74
90
|
# Lists assets with the specified tag.
|
@@ -87,7 +103,7 @@ class Cloudinary::Api
|
|
87
103
|
def self.resources_by_tag(tag, options={})
|
88
104
|
resource_type = options[:resource_type] || "image"
|
89
105
|
uri = "resources/#{resource_type}/tags/#{tag}"
|
90
|
-
call_api(:get, uri,
|
106
|
+
call_api(:get, uri, list_resources_params(options), options)
|
91
107
|
end
|
92
108
|
|
93
109
|
# Lists assets currently in the specified moderation queue and status.
|
@@ -107,7 +123,7 @@ class Cloudinary::Api
|
|
107
123
|
def self.resources_by_moderation(kind, status, options={})
|
108
124
|
resource_type = options[:resource_type] || "image"
|
109
125
|
uri = "resources/#{resource_type}/moderations/#{kind}/#{status}"
|
110
|
-
call_api(:get, uri,
|
126
|
+
call_api(:get, uri, list_resources_params(options), options)
|
111
127
|
end
|
112
128
|
|
113
129
|
# Lists assets with the specified contextual metadata.
|
@@ -129,30 +145,9 @@ class Cloudinary::Api
|
|
129
145
|
def self.resources_by_context(key, value=nil, options={})
|
130
146
|
resource_type = options[:resource_type] || "image"
|
131
147
|
uri = "resources/#{resource_type}/context"
|
132
|
-
|
133
|
-
params[:key] = key
|
134
|
-
params[:value] = value
|
135
|
-
call_api(:get, uri, params, options)
|
148
|
+
call_api(:get, uri, list_resources_params(options, :key => key, :value => value), options)
|
136
149
|
end
|
137
150
|
|
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
151
|
# Lists assets with the specified public IDs.
|
157
152
|
#
|
158
153
|
# @param [String|Array] public_ids The requested public_ids (up to 100).
|
@@ -168,7 +163,7 @@ class Cloudinary::Api
|
|
168
163
|
resource_type = options[:resource_type] || "image"
|
169
164
|
type = options[:type] || "upload"
|
170
165
|
uri = "resources/#{resource_type}/#{type}"
|
171
|
-
call_api(:get, uri,
|
166
|
+
call_api(:get, uri, resources_params(options, :public_ids => public_ids), options)
|
172
167
|
end
|
173
168
|
|
174
169
|
# Lists assets with the specified asset IDs.
|
@@ -184,9 +179,7 @@ class Cloudinary::Api
|
|
184
179
|
# @see https://cloudinary.com/documentation/admin_api#get_resources
|
185
180
|
def self.resources_by_asset_ids(asset_ids, options={})
|
186
181
|
uri = "resources/by_asset_ids"
|
187
|
-
|
188
|
-
params[:asset_ids] = asset_ids
|
189
|
-
call_api(:get, uri, params, options)
|
182
|
+
call_api(:get, uri, resources_params(options, :asset_ids => asset_ids), options)
|
190
183
|
end
|
191
184
|
|
192
185
|
# Returns all assets stored directly in a specified asset folder, regardless of the public ID paths of those assets.
|
@@ -202,9 +195,7 @@ class Cloudinary::Api
|
|
202
195
|
# @see https://cloudinary.com/documentation/dynamic_folders#new_admin_api_endpoints
|
203
196
|
def self.resources_by_asset_folder(asset_folder, options={})
|
204
197
|
uri = "resources/by_asset_folder"
|
205
|
-
|
206
|
-
params[:asset_folder] = asset_folder
|
207
|
-
call_api(:get, uri, params, options)
|
198
|
+
call_api(:get, uri, list_resources_params(options, :asset_folder => asset_folder), options)
|
208
199
|
end
|
209
200
|
|
210
201
|
# Find images based on their visual content.
|
@@ -216,8 +207,9 @@ class Cloudinary::Api
|
|
216
207
|
# @raise [Cloudinary::Api::Error]
|
217
208
|
def self.visual_search(options = {})
|
218
209
|
uri = "resources/visual_search"
|
219
|
-
params = only(options, :image_url, :image_asset_id, :text)
|
220
|
-
|
210
|
+
params = only(options, :image_url, :image_asset_id, :text, :image_file)
|
211
|
+
params[:image_file] = Cloudinary::Utils.handle_file_param(params[:image_file]) if params.has_key?(:image_file)
|
212
|
+
call_api(:post, uri, params, options)
|
221
213
|
end
|
222
214
|
|
223
215
|
# Returns the details of the specified asset and all its derived assets.
|
@@ -242,6 +234,23 @@ class Cloudinary::Api
|
|
242
234
|
call_api(:get, uri, prepare_resource_details_params(options), options)
|
243
235
|
end
|
244
236
|
|
237
|
+
# Returns the details of the specified asset and all its derived assets by asset id.
|
238
|
+
#
|
239
|
+
# Note that if you only need details about the original asset,
|
240
|
+
# you can also use the Uploader::upload or Uploader::explicit methods, which return the same information and
|
241
|
+
# are not rate limited.
|
242
|
+
#
|
243
|
+
# @param [String] asset_id The Asset ID of the asset.
|
244
|
+
# @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.
|
245
|
+
#
|
246
|
+
# @return [Cloudinary::Api::Response]
|
247
|
+
#
|
248
|
+
# @see https://cloudinary.com/documentation/admin_api#get_the_details_of_a_single_resource
|
249
|
+
def self.resource_by_asset_id(asset_id, options={})
|
250
|
+
uri = "resources/#{asset_id}"
|
251
|
+
call_api(:get, uri, prepare_resource_details_params(options), options)
|
252
|
+
end
|
253
|
+
|
245
254
|
# Reverts to the latest backed up version of the specified deleted assets.
|
246
255
|
#
|
247
256
|
# @param [String|Array] public_ids The public IDs of the backed up assets to restore. They can be existing or
|
@@ -656,7 +665,7 @@ class Cloudinary::Api
|
|
656
665
|
#
|
657
666
|
# @see https://cloudinary.com/documentation/admin_api#update_an_upload_preset
|
658
667
|
def self.update_upload_preset(name, options={})
|
659
|
-
params = Cloudinary::Uploader.build_upload_params(options)
|
668
|
+
params = Cloudinary::Uploader.build_upload_params(options, true)
|
660
669
|
call_api(:put, "upload_presets/#{name}", params.merge(only(options, :unsigned, :disallow_public_id, :live)), options)
|
661
670
|
end
|
662
671
|
|
@@ -671,7 +680,7 @@ class Cloudinary::Api
|
|
671
680
|
#
|
672
681
|
# @see https://cloudinary.com/documentation/admin_api#create_an_upload_preset
|
673
682
|
def self.create_upload_preset(options={})
|
674
|
-
params = Cloudinary::Uploader.build_upload_params(options)
|
683
|
+
params = Cloudinary::Uploader.build_upload_params(options, true)
|
675
684
|
call_api(:post, "upload_presets", params.merge(only(options, :name, :unsigned, :disallow_public_id, :live)), options)
|
676
685
|
end
|
677
686
|
|
@@ -738,6 +747,21 @@ class Cloudinary::Api
|
|
738
747
|
call_api(:post, "folders/#{folder_name}", {}, options)
|
739
748
|
end
|
740
749
|
|
750
|
+
# Renames existing asset folder.
|
751
|
+
#
|
752
|
+
# @param [String] from_path The full path of an existing asset folder.
|
753
|
+
# @param [String] to_path The full path of the new asset folder.
|
754
|
+
# @param [Hash] options The optional parameters.
|
755
|
+
#
|
756
|
+
# @return [Cloudinary::Api::Response]
|
757
|
+
#
|
758
|
+
# @raise [Cloudinary::Api::Error]
|
759
|
+
#
|
760
|
+
# @see https://cloudinary.com/documentation/admin_api#rename_folder
|
761
|
+
def self.rename_folder(from_path, to_path, options={})
|
762
|
+
call_api(:put, "folders/#{from_path}", {:to_folder => to_path}, options)
|
763
|
+
end
|
764
|
+
|
741
765
|
# Lists upload mappings by folder and its mapped template (URL).
|
742
766
|
#
|
743
767
|
# @param [Hash] options The optional parameters. See the
|
@@ -1013,9 +1037,7 @@ class Cloudinary::Api
|
|
1013
1037
|
#
|
1014
1038
|
# @see https://cloudinary.com/documentation/admin_api#create_a_metadata_field
|
1015
1039
|
def self.add_metadata_field(field, options = {})
|
1016
|
-
|
1017
|
-
|
1018
|
-
call_metadata_api(:post, [], params, options)
|
1040
|
+
call_metadata_api(:post, [], prepare_metadata_field_params(field), options)
|
1019
1041
|
end
|
1020
1042
|
|
1021
1043
|
# Updates a metadata field by external ID.
|
@@ -1032,10 +1054,19 @@ class Cloudinary::Api
|
|
1032
1054
|
#
|
1033
1055
|
# @see https://cloudinary.com/documentation/admin_api#update_a_metadata_field_by_external_id
|
1034
1056
|
def self.update_metadata_field(field_external_id, field, options = {})
|
1035
|
-
uri
|
1036
|
-
params = only(field, :label, :mandatory, :default_value, :validation)
|
1057
|
+
uri = [field_external_id]
|
1037
1058
|
|
1038
|
-
call_metadata_api(:put, uri,
|
1059
|
+
call_metadata_api(:put, uri, prepare_metadata_field_params(field), options)
|
1060
|
+
end
|
1061
|
+
|
1062
|
+
# Prepares optional parameters for add/update_metadata_field API calls.
|
1063
|
+
# @param [Hash] options Additional options
|
1064
|
+
# @return [Object] Optional parameters
|
1065
|
+
def self.prepare_metadata_field_params(field)
|
1066
|
+
only(field,
|
1067
|
+
:type, :external_id, :label, :mandatory, :restrictions, :default_value, :default_disabled,
|
1068
|
+
:validation, :datasource, :allow_dynamic_list_values
|
1069
|
+
)
|
1039
1070
|
end
|
1040
1071
|
|
1041
1072
|
# Deletes a metadata field definition by external ID.
|
@@ -1229,6 +1260,25 @@ class Cloudinary::Api
|
|
1229
1260
|
call_metadata_rules_api(:delete, uri, {}, options)
|
1230
1261
|
end
|
1231
1262
|
|
1263
|
+
# Analyzes an asset with the requested analysis type.
|
1264
|
+
#
|
1265
|
+
# @param [Object] input_type The type of input for the asset to analyze ('uri').
|
1266
|
+
# @param [Object] analysis_type The type of analysis to run ('google_tagging', 'captioning', 'fashion').
|
1267
|
+
# @param [Hash] options The optional parameters.
|
1268
|
+
#
|
1269
|
+
# @return [Cloudinary::Api::Response]
|
1270
|
+
#
|
1271
|
+
# @raise [Cloudinary::Api::Error]
|
1272
|
+
def self.analyze(input_type, analysis_type, options = {})
|
1273
|
+
api_uri = ["analysis", "analyze", input_type]
|
1274
|
+
params = only(options, :uri, :parameters)
|
1275
|
+
params["analysis_type"] = analysis_type
|
1276
|
+
|
1277
|
+
options[:api_version] = 'v2'
|
1278
|
+
|
1279
|
+
call_api(:post, api_uri, params, options)
|
1280
|
+
end
|
1281
|
+
|
1232
1282
|
protected
|
1233
1283
|
|
1234
1284
|
# Execute a call api for input params.
|
@@ -1243,13 +1293,14 @@ class Cloudinary::Api
|
|
1243
1293
|
api_key = options[:api_key] || Cloudinary.config.api_key
|
1244
1294
|
api_secret = options[:api_secret] || Cloudinary.config.api_secret
|
1245
1295
|
oauth_token = options[:oauth_token] || Cloudinary.config.oauth_token
|
1296
|
+
api_version = options[:api_version] || Cloudinary.config.api_version || 'v1_1'
|
1246
1297
|
|
1247
1298
|
validate_authorization(api_key, api_secret, oauth_token)
|
1248
1299
|
|
1249
1300
|
auth = { :key => api_key, :secret => api_secret, :oauth_token => oauth_token }
|
1250
1301
|
|
1251
1302
|
call_cloudinary_api(method, uri, auth, params, options) do |cloudinary, inner_uri|
|
1252
|
-
[cloudinary,
|
1303
|
+
[cloudinary, api_version, cloud_name, inner_uri]
|
1253
1304
|
end
|
1254
1305
|
end
|
1255
1306
|
|
@@ -1261,7 +1312,7 @@ class Cloudinary::Api
|
|
1261
1312
|
return Cloudinary::Utils.json_decode(response.body)
|
1262
1313
|
rescue => e
|
1263
1314
|
# Error is parsing json
|
1264
|
-
raise GeneralError.new("Error parsing server response (#{response.
|
1315
|
+
raise GeneralError.new("Error parsing server response (#{response.status}) - #{response.body}. Got - #{e}")
|
1265
1316
|
end
|
1266
1317
|
|
1267
1318
|
# Protected function that assists with performing an API call to the metadata_fields part of the Admin API.
|
@@ -1398,4 +1449,19 @@ class Cloudinary::Api
|
|
1398
1449
|
params[by_key] = value
|
1399
1450
|
call_api("post", "resources/#{resource_type}/#{type}/update_access_mode", params, options)
|
1400
1451
|
end
|
1452
|
+
|
1453
|
+
private
|
1454
|
+
|
1455
|
+
RESOURCES_PARAMS = [:tags, :context, :metadata, :moderations, :fields].freeze
|
1456
|
+
LIST_RESOURCES_PARAMS = [:next_cursor, :max_results, :direction].freeze
|
1457
|
+
|
1458
|
+
def self.resources_params(options, params = {})
|
1459
|
+
params.merge!(only(options, *RESOURCES_PARAMS))
|
1460
|
+
params[:fields] = Cloudinary::Utils.build_array(options[:fields]).join(",") unless params[:fields].nil?
|
1461
|
+
params
|
1462
|
+
end
|
1463
|
+
|
1464
|
+
def self.list_resources_params(options, params = {})
|
1465
|
+
params.merge(resources_params(options)).merge!(only(options, *LIST_RESOURCES_PARAMS))
|
1466
|
+
end
|
1401
1467
|
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, 429 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.respond_to?(:upload_chunked?) && 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
|
@@ -82,14 +83,7 @@ class Cloudinary::CarrierWave::Storage < ::CarrierWave::Storage::Abstract
|
|
82
83
|
end
|
83
84
|
|
84
85
|
if defined?(ActiveRecord::Base) && uploader.model.is_a?(ActiveRecord::Base)
|
85
|
-
|
86
|
-
if defined?(::ActiveRecord::VERSION::MAJOR) && ::ActiveRecord::VERSION::MAJOR > 2
|
87
|
-
model_class.where(primary_key=>uploader.model.send(primary_key)).update_all(column=>name)
|
88
|
-
else
|
89
|
-
# Removed since active record version 3.0.0
|
90
|
-
model_class.update_all({column=>name}, {primary_key=>uploader.model.send(primary_key)})
|
91
|
-
end
|
92
|
-
uploader.model.send :write_attribute, column, name
|
86
|
+
uploader.model.update_column(column, name)
|
93
87
|
elsif defined?(Mongoid::Document) && uploader.model.is_a?(Mongoid::Document)
|
94
88
|
# Mongoid support
|
95
89
|
if Mongoid::VERSION.split(".").first.to_i >= 4
|
data/lib/cloudinary/helper.rb
CHANGED
@@ -179,7 +179,7 @@ module CloudinaryHelper
|
|
179
179
|
version_store = options.delete(:version_store)
|
180
180
|
if options[:version].blank? && (version_store == :file) && defined?(Rails) && defined?(Rails.root)
|
181
181
|
file_name = "#{Rails.root}/tmp/cloudinary/cloudinary_sprite_#{source.sub(/\..*/, '')}.version"
|
182
|
-
if File.
|
182
|
+
if File.exist?(file_name)
|
183
183
|
options[:version] = File.read(file_name).chomp
|
184
184
|
end
|
185
185
|
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.
|
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])
|