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
data/lib/cloudinary/migrator.rb
CHANGED
@@ -6,29 +6,29 @@ class Cloudinary::Migrator
|
|
6
6
|
attr_reader :db
|
7
7
|
attr_reader :work, :results, :mutex
|
8
8
|
attr_reader :extra_options
|
9
|
-
|
10
|
-
|
9
|
+
|
10
|
+
|
11
11
|
@@init = false
|
12
12
|
def self.init
|
13
13
|
return if @@init
|
14
14
|
@@init = true
|
15
15
|
|
16
|
-
begin
|
16
|
+
begin
|
17
17
|
require 'sqlite3'
|
18
18
|
rescue LoadError
|
19
|
-
raise "Please add sqlite3 to your Gemfile"
|
19
|
+
raise "Please add sqlite3 to your Gemfile"
|
20
20
|
end
|
21
21
|
require 'tempfile'
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
def json_decode(str)
|
25
25
|
Cloudinary::Utils.json_decode(str)
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
def initialize(options={})
|
29
29
|
self.class.init
|
30
|
-
|
31
|
-
options[:db_file] = "tmp/migration#{$$}.db" if options[:private_database] && !options[:db_file]
|
30
|
+
|
31
|
+
options[:db_file] = "tmp/migration#{$$}.db" if options[:private_database] && !options[:db_file]
|
32
32
|
@dbfile = options[:db_file] || "tmp/migration.db"
|
33
33
|
FileUtils.mkdir_p(File.dirname(@dbfile))
|
34
34
|
@db = SQLite3::Database.new @dbfile, :results_as_hash=>true
|
@@ -37,7 +37,6 @@ class Cloudinary::Migrator
|
|
37
37
|
@debug = options[:debug] || false
|
38
38
|
@ignore_duplicates = options[:ignore_duplicates]
|
39
39
|
@threads = [options[:threads] || 10, 100].min
|
40
|
-
@threads = 1 if RUBY_VERSION < "1.9"
|
41
40
|
@extra_options = {:api_key=>options[:api_key], :api_secret=>options[:api_secret]}
|
42
41
|
@delete_after_done = options[:delete_after_done] || options[:private_database]
|
43
42
|
@max_processing = @threads * 10
|
@@ -77,7 +76,7 @@ class Cloudinary::Migrator
|
|
77
76
|
@db.execute("delete from queue")
|
78
77
|
end
|
79
78
|
end
|
80
|
-
|
79
|
+
|
81
80
|
def register_retrieve(&block)
|
82
81
|
@retrieve = block
|
83
82
|
end
|
@@ -85,26 +84,26 @@ class Cloudinary::Migrator
|
|
85
84
|
def register_complete(&block)
|
86
85
|
@complete = block
|
87
86
|
end
|
88
|
-
|
89
|
-
def process(options={})
|
87
|
+
|
88
|
+
def process(options={})
|
90
89
|
raise CloudinaryException, "url not given and no retrieve callback given" if options[:url].nil? && self.retrieve.nil?
|
91
90
|
raise CloudinaryException, "id not given and retrieve or complete callback given" if options[:id].nil? && (!self.retrieve.nil? || !self.complete.nil?)
|
92
91
|
|
93
92
|
debug("Process: #{options.inspect}")
|
94
93
|
start
|
95
|
-
process_results
|
94
|
+
process_results
|
96
95
|
wait_for_queue
|
97
96
|
options = options.dup
|
98
97
|
id = options.delete(:id)
|
99
98
|
url = options.delete(:url)
|
100
99
|
public_id = options.delete(:public_id)
|
101
100
|
row = {
|
102
|
-
"internal_id"=>id,
|
103
|
-
"url"=>url,
|
104
|
-
"public_id"=>public_id,
|
101
|
+
"internal_id"=>id,
|
102
|
+
"url"=>url,
|
103
|
+
"public_id"=>public_id,
|
105
104
|
"metadata"=>options.to_json,
|
106
|
-
"status"=>"processing"
|
107
|
-
}
|
105
|
+
"status"=>"processing"
|
106
|
+
}
|
108
107
|
begin
|
109
108
|
insert_row(row)
|
110
109
|
add_to_work_queue(row)
|
@@ -112,7 +111,7 @@ class Cloudinary::Migrator
|
|
112
111
|
raise if !@ignore_duplicates
|
113
112
|
end
|
114
113
|
end
|
115
|
-
|
114
|
+
|
116
115
|
def done
|
117
116
|
start
|
118
117
|
process_all_pending
|
@@ -122,37 +121,37 @@ class Cloudinary::Migrator
|
|
122
121
|
@db.close
|
123
122
|
File.delete(@dbfile) if @delete_after_done
|
124
123
|
end
|
125
|
-
|
124
|
+
|
126
125
|
def max_given_id
|
127
126
|
db.get_first_value("select max(internal_id) from queue").to_i
|
128
127
|
end
|
129
|
-
|
128
|
+
|
130
129
|
def close_if_needed(file)
|
131
130
|
if file.nil?
|
132
131
|
# Do nothing.
|
133
|
-
elsif file.respond_to?(:close!)
|
134
|
-
file.close!
|
132
|
+
elsif file.respond_to?(:close!)
|
133
|
+
file.close!
|
135
134
|
elsif file.respond_to?(:close)
|
136
135
|
file.close
|
137
136
|
end
|
138
137
|
rescue
|
139
138
|
# Ignore errors in closing files
|
140
|
-
end
|
139
|
+
end
|
141
140
|
|
142
|
-
def temporary_file(data, filename)
|
143
|
-
file =
|
141
|
+
def temporary_file(data, filename)
|
142
|
+
file = Tempfile.new('cloudinary', :encoding => 'ascii-8bit')
|
144
143
|
file.unlink
|
145
144
|
file.write(data)
|
146
145
|
file.rewind
|
147
|
-
# Tempfile return path == nil after unlink, which break rest-client
|
146
|
+
# Tempfile return path == nil after unlink, which break rest-client
|
148
147
|
class << file
|
149
148
|
attr_accessor :original_filename
|
150
149
|
def content_type
|
151
|
-
"application/octet-stream"
|
150
|
+
"application/octet-stream"
|
152
151
|
end
|
153
152
|
end
|
154
153
|
file.original_filename = filename
|
155
|
-
file
|
154
|
+
file
|
156
155
|
end
|
157
156
|
|
158
157
|
private
|
@@ -160,21 +159,21 @@ class Cloudinary::Migrator
|
|
160
159
|
def update_all(values)
|
161
160
|
@db.execute("update queue set #{values.keys.map{|key| "#{key}=?"}.join(",")}", *values.values)
|
162
161
|
end
|
163
|
-
|
164
|
-
def update_row(row, values)
|
162
|
+
|
163
|
+
def update_row(row, values)
|
165
164
|
values.merge!("updated_at"=>Time.now.to_i)
|
166
165
|
query = ["update queue set #{values.keys.map{|key| "#{key}=?"}.join(",")} where id=?"] + values.values + [row["id"]]
|
167
166
|
@db.execute(*query)
|
168
167
|
values.each{|key, value| row[key.to_s] = value}
|
169
|
-
row
|
168
|
+
row
|
170
169
|
end
|
171
|
-
|
170
|
+
|
172
171
|
def insert_row(values)
|
173
172
|
values.merge!("updated_at"=>Time.now.to_i)
|
174
173
|
@db.execute("insert into queue (#{values.keys.join(",")}) values (#{values.keys.map{"?"}.join(",")})", *values.values)
|
175
174
|
values["id"] = @db.last_insert_row_id
|
176
175
|
end
|
177
|
-
|
176
|
+
|
178
177
|
def refill_queue(last_id)
|
179
178
|
@db.execute("select * from queue where status in ('error', 'processing') and id > ? limit ?", last_id, 10000) do
|
180
179
|
|row|
|
@@ -183,25 +182,25 @@ class Cloudinary::Migrator
|
|
183
182
|
add_to_work_queue(row)
|
184
183
|
end
|
185
184
|
last_id
|
186
|
-
end
|
185
|
+
end
|
187
186
|
|
188
187
|
def process_results
|
189
188
|
while self.results.length > 0
|
190
189
|
row = self.results.pop
|
191
|
-
result = json_decode(row["result"])
|
190
|
+
result = json_decode(row["result"])
|
192
191
|
debug("Done ID=#{row['internal_id']}, result=#{result.inspect}")
|
193
|
-
complete.call(row["internal_id"], result) if complete
|
194
|
-
if result["error"]
|
192
|
+
complete.call(row["internal_id"], result) if complete
|
193
|
+
if result["error"]
|
195
194
|
status = case result["error"]["http_code"]
|
196
195
|
when 400, 404 then "fatal" # Problematic request. Not a server problem.
|
197
196
|
else "error"
|
198
197
|
end
|
199
198
|
else
|
200
199
|
status = "completed"
|
201
|
-
end
|
200
|
+
end
|
202
201
|
updates = {:status=>status, :result=>row["result"]}
|
203
202
|
updates["public_id"] = result["public_id"] if result["public_id"] && !row["public_id"]
|
204
|
-
begin
|
203
|
+
begin
|
205
204
|
update_row(row, updates)
|
206
205
|
rescue SQLite3::ConstraintException
|
207
206
|
updates = {:status=>"error", :result=>{:error=>{:message=>"public_id already exists"}}.to_json}
|
@@ -219,16 +218,16 @@ class Cloudinary::Migrator
|
|
219
218
|
raise if retry_count > tries
|
220
219
|
sleep rand * 3
|
221
220
|
retry
|
222
|
-
end
|
221
|
+
end
|
223
222
|
end
|
224
|
-
|
223
|
+
|
225
224
|
def start
|
226
225
|
return if @started
|
227
226
|
@started = true
|
228
227
|
@terminate = false
|
229
|
-
|
228
|
+
|
230
229
|
self.work.clear
|
231
|
-
|
230
|
+
|
232
231
|
main = self
|
233
232
|
Thread.abort_on_exception = true
|
234
233
|
1.upto(@threads) do
|
@@ -251,8 +250,8 @@ class Cloudinary::Migrator
|
|
251
250
|
elsif defined?(::CarrierWave) && defined?(Cloudinary::CarrierWave) && data.is_a?(Cloudinary::CarrierWave)
|
252
251
|
cw = true
|
253
252
|
begin
|
254
|
-
data.model.save!
|
255
|
-
rescue Cloudinary::CarrierWave::UploadError
|
253
|
+
data.model.save!
|
254
|
+
rescue Cloudinary::CarrierWave::UploadError
|
256
255
|
# upload errors will be handled by the result values.
|
257
256
|
end
|
258
257
|
result = data.metadata
|
@@ -264,22 +263,22 @@ class Cloudinary::Migrator
|
|
264
263
|
elsif data.match(/^https?:/)
|
265
264
|
url = data
|
266
265
|
else
|
267
|
-
file = main.temporary_file(data, row["public_id"] || "cloudinaryfile")
|
266
|
+
file = main.temporary_file(data, row["public_id"] || "cloudinaryfile")
|
268
267
|
end
|
269
268
|
end
|
270
|
-
|
269
|
+
|
271
270
|
if url || file
|
272
271
|
options = main.extra_options.merge(:public_id=>row["public_id"])
|
273
272
|
json_decode(row["metadata"]).each do
|
274
273
|
|key, value|
|
275
274
|
options[key.to_sym] = value
|
276
275
|
end
|
277
|
-
|
276
|
+
|
278
277
|
result = Cloudinary::Uploader.upload(url || file, options.merge(:return_error=>true)) || ({:error=>{:message=>"Received nil from uploader!"}})
|
279
278
|
elsif cw
|
280
279
|
result ||= {"status" => "saved"}
|
281
280
|
else
|
282
|
-
result = {"error" => {"message" => "Empty data and url", "http_code"=>404}}
|
281
|
+
result = {"error" => {"message" => "Empty data and url", "http_code"=>404}}
|
283
282
|
end
|
284
283
|
main.results << {"id"=>row["id"], "internal_id"=>row["internal_id"], "result"=>result.to_json}
|
285
284
|
rescue => e
|
@@ -289,14 +288,14 @@ class Cloudinary::Migrator
|
|
289
288
|
ensure
|
290
289
|
main.mutex.synchronize{main.in_process -= 1}
|
291
290
|
main.close_if_needed(file)
|
292
|
-
end
|
291
|
+
end
|
293
292
|
end
|
294
293
|
end
|
295
|
-
end
|
296
|
-
|
294
|
+
end
|
295
|
+
|
297
296
|
retry_previous_queue # Retry all work from previous iteration before we start processing this one.
|
298
297
|
end
|
299
|
-
|
298
|
+
|
300
299
|
def debug(message)
|
301
300
|
if @debug
|
302
301
|
mutex.synchronize{
|
@@ -310,60 +309,60 @@ class Cloudinary::Migrator
|
|
310
309
|
begin
|
311
310
|
prev_last_id, last_id = last_id, refill_queue(last_id)
|
312
311
|
end while last_id > prev_last_id
|
313
|
-
process_results
|
312
|
+
process_results
|
314
313
|
end
|
315
|
-
|
314
|
+
|
316
315
|
def process_all_pending
|
317
316
|
# Waiting for work to finish. While we are at it, process results.
|
318
|
-
while self.in_process > 0
|
317
|
+
while self.in_process > 0
|
319
318
|
process_results
|
320
319
|
sleep 0.1
|
321
320
|
end
|
322
321
|
# Make sure we processed all the results
|
323
322
|
process_results
|
324
323
|
end
|
325
|
-
|
324
|
+
|
326
325
|
def add_to_work_queue(row)
|
327
326
|
self.work << row
|
328
327
|
mutex.synchronize{self.in_process += 1}
|
329
328
|
end
|
330
|
-
|
329
|
+
|
331
330
|
def wait_for_queue
|
332
331
|
# Waiting f
|
333
332
|
while self.work.length > @max_processing
|
334
|
-
process_results
|
333
|
+
process_results
|
335
334
|
sleep 0.1
|
336
|
-
end
|
335
|
+
end
|
337
336
|
end
|
338
337
|
|
339
|
-
def self.sample
|
338
|
+
def self.sample
|
340
339
|
migrator = Cloudinary::Migrator.new(
|
341
|
-
:retrieve=>proc{|id| Post.find(id).data},
|
340
|
+
:retrieve=>proc{|id| Post.find(id).data},
|
342
341
|
:complete=>proc{|id, result| a}
|
343
342
|
)
|
344
|
-
|
343
|
+
|
345
344
|
Post.find_each(:conditions=>["id > ?", migrator.max_given_id], :select=>"id") do
|
346
345
|
|post|
|
347
346
|
migrator.process(:id=>post.id, :public_id=>"post_#{post.id}")
|
348
347
|
end
|
349
348
|
migrator.done
|
350
|
-
end
|
351
|
-
|
352
|
-
def self.test
|
349
|
+
end
|
350
|
+
|
351
|
+
def self.test
|
353
352
|
posts = {}
|
354
|
-
done = {}
|
353
|
+
done = {}
|
355
354
|
migrator = Cloudinary::Migrator.new(
|
356
|
-
:retrieve=>proc{|id| posts[id]},
|
355
|
+
:retrieve=>proc{|id| posts[id]},
|
357
356
|
:complete=>proc{|id, result| $stderr.print "done #{id} #{result}\n"; done[id] = result}
|
358
357
|
)
|
359
358
|
start = migrator.max_given_id + 1
|
360
359
|
(start..1000).each{|i| posts[i] = "hello#{i}"}
|
361
|
-
|
360
|
+
|
362
361
|
posts.each do
|
363
362
|
|id, data|
|
364
363
|
migrator.process(:id=>id, :public_id=>"post_#{id}")
|
365
364
|
end
|
366
365
|
migrator.done
|
367
366
|
pp [done.length, start]
|
368
|
-
end
|
367
|
+
end
|
369
368
|
end
|
data/lib/cloudinary/railtie.rb
CHANGED
@@ -3,7 +3,9 @@ class Cloudinary::Railtie < Rails::Railtie
|
|
3
3
|
Dir[File.join(File.dirname(__FILE__),'../tasks/**/*.rake')].each { |f| load f }
|
4
4
|
end
|
5
5
|
config.after_initialize do |app|
|
6
|
-
|
6
|
+
ActiveSupport.on_load(:action_view) do
|
7
|
+
ActionView::Base.send :include, CloudinaryHelper
|
8
|
+
end
|
7
9
|
end
|
8
10
|
|
9
11
|
ActiveSupport.on_load(:action_controller_base) do
|
data/lib/cloudinary/search.rb
CHANGED
@@ -4,7 +4,8 @@ class Cloudinary::Search
|
|
4
4
|
SORT_BY = :sort_by
|
5
5
|
AGGREGATE = :aggregate
|
6
6
|
WITH_FIELD = :with_field
|
7
|
-
|
7
|
+
FIELDS = :fields
|
8
|
+
KEYS_WITH_UNIQUE_VALUES = [SORT_BY, AGGREGATE, WITH_FIELD, FIELDS].freeze
|
8
9
|
|
9
10
|
TTL = 300 # Used for search URLs
|
10
11
|
|
@@ -12,7 +13,8 @@ class Cloudinary::Search
|
|
12
13
|
@query_hash = {
|
13
14
|
SORT_BY => {},
|
14
15
|
AGGREGATE => {},
|
15
|
-
WITH_FIELD => {}
|
16
|
+
WITH_FIELD => {},
|
17
|
+
FIELDS => {},
|
16
18
|
}
|
17
19
|
|
18
20
|
@endpoint = self.class::ENDPOINT
|
@@ -59,7 +61,7 @@ class Cloudinary::Search
|
|
59
61
|
#
|
60
62
|
# @param [String] value Supported values: resource_type, type, pixels (only the image assets in the response are
|
61
63
|
# aggregated), duration (only the video assets in the response are aggregated), format, and
|
62
|
-
# bytes. For aggregation fields without discrete values, the results are divided into
|
64
|
+
# bytes. For aggregation fields without discrete values, the results are divided into
|
63
65
|
# categories.
|
64
66
|
# @return [Cloudinary::Search]
|
65
67
|
def aggregate(value)
|
@@ -77,6 +79,19 @@ class Cloudinary::Search
|
|
77
79
|
self
|
78
80
|
end
|
79
81
|
|
82
|
+
|
83
|
+
# The list of the asset attributes to include for each asset in the response.
|
84
|
+
#
|
85
|
+
# @param [Array] value The array of attributes' names.
|
86
|
+
#
|
87
|
+
# @return [Cloudinary::Search]
|
88
|
+
def fields(value)
|
89
|
+
Cloudinary::Utils.build_array(value).each do |field|
|
90
|
+
@query_hash[FIELDS][field] = field
|
91
|
+
end
|
92
|
+
self
|
93
|
+
end
|
94
|
+
|
80
95
|
# Sets the time to live of the search URL.
|
81
96
|
#
|
82
97
|
# @param [Object] ttl The time to live in seconds.
|
data/lib/cloudinary/uploader.rb
CHANGED
@@ -1,82 +1,53 @@
|
|
1
1
|
# Copyright Cloudinary
|
2
|
-
require '
|
2
|
+
require 'faraday'
|
3
3
|
require 'json'
|
4
4
|
require 'cloudinary/cache'
|
5
5
|
|
6
6
|
class Cloudinary::Uploader
|
7
|
-
|
8
|
-
|
9
|
-
# @deprecated use {Cloudinary::Utils.build_eager} instead
|
10
|
-
def self.build_eager(eager)
|
11
|
-
Cloudinary::Utils.build_eager(eager)
|
12
|
-
end
|
13
|
-
|
14
|
-
# @private
|
15
|
-
def self.build_upload_params(options)
|
7
|
+
@adapter = nil
|
8
|
+
def self.build_upload_params(options, as_bool = false)
|
16
9
|
#symbolize keys
|
17
10
|
options = options.clone
|
18
11
|
options.keys.each { |key| options[key.to_sym] = options.delete(key) if key.is_a?(String) }
|
19
12
|
|
20
13
|
params = {
|
21
|
-
:access_control
|
22
|
-
:
|
23
|
-
:
|
24
|
-
:
|
25
|
-
:
|
26
|
-
:
|
27
|
-
:
|
28
|
-
:
|
29
|
-
:
|
30
|
-
:
|
31
|
-
:
|
32
|
-
:
|
33
|
-
:
|
34
|
-
:custom_coordinates => Cloudinary::Utils.encode_double_array(options[:custom_coordinates]),
|
35
|
-
:detection => options[:detection],
|
36
|
-
:discard_original_filename => Cloudinary::Utils.as_safe_bool(options[:discard_original_filename]),
|
37
|
-
:display_name => options[:display_name],
|
38
|
-
:eager => Cloudinary::Utils.build_eager(options[:eager]),
|
39
|
-
:eager_async => Cloudinary::Utils.as_safe_bool(options[:eager_async]),
|
40
|
-
:eager_notification_url => options[:eager_notification_url],
|
41
|
-
:exif => Cloudinary::Utils.as_safe_bool(options[:exif]),
|
42
|
-
:eval => options[:eval],
|
43
|
-
:face_coordinates => Cloudinary::Utils.encode_double_array(options[:face_coordinates]),
|
44
|
-
:faces => Cloudinary::Utils.as_safe_bool(options[:faces]),
|
45
|
-
:folder => options[:folder],
|
46
|
-
:format => options[:format],
|
47
|
-
:filename_override => options[:filename_override],
|
48
|
-
:headers => build_custom_headers(options[:headers]),
|
49
|
-
:image_metadata => Cloudinary::Utils.as_safe_bool(options[:image_metadata]),
|
50
|
-
:media_metadata => Cloudinary::Utils.as_safe_bool(options[:media_metadata]),
|
51
|
-
:invalidate => Cloudinary::Utils.as_safe_bool(options[:invalidate]),
|
52
|
-
:moderation => options[:moderation],
|
53
|
-
:notification_url => options[:notification_url],
|
54
|
-
:ocr => options[:ocr],
|
55
|
-
:overwrite => Cloudinary::Utils.as_safe_bool(options[:overwrite]),
|
56
|
-
:phash => Cloudinary::Utils.as_safe_bool(options[:phash]),
|
57
|
-
:proxy => options[:proxy],
|
58
|
-
:public_id => options[:public_id],
|
59
|
-
:public_id_prefix => options[:public_id_prefix],
|
60
|
-
:quality_analysis => Cloudinary::Utils.as_safe_bool(options[:quality_analysis]),
|
61
|
-
:quality_override => options[:quality_override],
|
62
|
-
:raw_convert => options[:raw_convert],
|
63
|
-
:responsive_breakpoints => Cloudinary::Utils.generate_responsive_breakpoints_string(options[:responsive_breakpoints]),
|
64
|
-
:return_delete_token => Cloudinary::Utils.as_safe_bool(options[:return_delete_token]),
|
65
|
-
:similarity_search => options[:similarity_search],
|
66
|
-
:visual_search => Cloudinary::Utils.as_safe_bool(options[:visual_search]),
|
67
|
-
:tags => options[:tags] && Cloudinary::Utils.build_array(options[:tags]).join(","),
|
68
|
-
:timestamp => (options[:timestamp] || Time.now.to_i),
|
69
|
-
:transformation => Cloudinary::Utils.generate_transformation_string(options.clone),
|
70
|
-
:type => options[:type],
|
71
|
-
:unique_filename => Cloudinary::Utils.as_safe_bool(options[:unique_filename]),
|
72
|
-
:upload_preset => options[:upload_preset],
|
73
|
-
:use_filename => Cloudinary::Utils.as_safe_bool(options[:use_filename]),
|
74
|
-
:use_filename_as_display_name => Cloudinary::Utils.as_safe_bool(options[:use_filename_as_display_name]),
|
75
|
-
:use_asset_folder_as_public_id_prefix => Cloudinary::Utils.as_safe_bool(options[:use_asset_folder_as_public_id_prefix]),
|
76
|
-
:unique_display_name => Cloudinary::Utils.as_safe_bool(options[:unique_display_name]),
|
77
|
-
:accessibility_analysis => Cloudinary::Utils.as_safe_bool(options[:accessibility_analysis]),
|
78
|
-
:metadata => Cloudinary::Utils.encode_context(options[:metadata])
|
14
|
+
:access_control => Cloudinary::Utils.json_array_param(options[:access_control]),
|
15
|
+
:allowed_formats => Cloudinary::Utils.build_array(options[:allowed_formats]).join(","),
|
16
|
+
:auto_tagging => options[:auto_tagging] && options[:auto_tagging].to_f,
|
17
|
+
:context => Cloudinary::Utils.encode_context(options[:context]),
|
18
|
+
:custom_coordinates => Cloudinary::Utils.encode_double_array(options[:custom_coordinates]),
|
19
|
+
:eager => Cloudinary::Utils.build_eager(options[:eager]),
|
20
|
+
:face_coordinates => Cloudinary::Utils.encode_double_array(options[:face_coordinates]),
|
21
|
+
:headers => build_custom_headers(options[:headers]),
|
22
|
+
:responsive_breakpoints => Cloudinary::Utils.generate_responsive_breakpoints_string(options[:responsive_breakpoints]),
|
23
|
+
:tags => options[:tags] && Cloudinary::Utils.build_array(options[:tags]).join(","),
|
24
|
+
:timestamp => (options[:timestamp] || Time.now.to_i),
|
25
|
+
:transformation => Cloudinary::Utils.generate_transformation_string(options.clone),
|
26
|
+
:metadata => Cloudinary::Utils.encode_context(options[:metadata])
|
79
27
|
}
|
28
|
+
|
29
|
+
bool_params = [
|
30
|
+
:async, :backup, :cinemagraph_analysis, :colors, :discard_original_filename, :eager_async, :exif, :faces,
|
31
|
+
:image_metadata, :media_metadata, :invalidate, :overwrite, :phash, :quality_analysis, :return_delete_token,
|
32
|
+
:visual_search, :unique_filename, :use_filename, :use_filename_as_display_name,
|
33
|
+
:use_asset_folder_as_public_id_prefix, :unique_display_name, :accessibility_analysis
|
34
|
+
]
|
35
|
+
|
36
|
+
string_params = [
|
37
|
+
:access_mode, :asset_folder, :background_removal, :callback, :categorization, :detection, :display_name,
|
38
|
+
:eager_notification_url, :eval, :on_success, :folder, :format, :filename_override, :moderation, :notification_url,
|
39
|
+
:ocr, :proxy, :public_id, :public_id_prefix, :quality_override, :raw_convert, :similarity_search, :type,
|
40
|
+
:upload_preset
|
41
|
+
]
|
42
|
+
|
43
|
+
bool_params.each do |b|
|
44
|
+
params[b] = as_bool ? Cloudinary::Utils.as_bool(options[b]): Cloudinary::Utils.as_safe_bool(options[b])
|
45
|
+
end
|
46
|
+
|
47
|
+
string_params.each do |s|
|
48
|
+
params[s] = options[s]
|
49
|
+
end
|
50
|
+
|
80
51
|
params
|
81
52
|
end
|
82
53
|
|
@@ -87,16 +58,7 @@ class Cloudinary::Uploader
|
|
87
58
|
def self.upload(file, options={})
|
88
59
|
call_api("upload", options) do
|
89
60
|
params = build_upload_params(options)
|
90
|
-
|
91
|
-
params[:file] = File.open(file, "rb")
|
92
|
-
elsif file.is_a?(StringIO)
|
93
|
-
file.rewind
|
94
|
-
params[:file] = Cloudinary::Blob.new(file.read, options)
|
95
|
-
elsif file.respond_to?(:read) || Cloudinary::Utils.is_remote?(file)
|
96
|
-
params[:file] = file
|
97
|
-
else
|
98
|
-
params[:file] = File.open(file, "rb")
|
99
|
-
end
|
61
|
+
params[:file] = Cloudinary::Utils.handle_file_param(file, options)
|
100
62
|
[params, [:file]]
|
101
63
|
end
|
102
64
|
end
|
@@ -153,11 +115,7 @@ class Cloudinary::Uploader
|
|
153
115
|
options[:resource_type] ||= :raw
|
154
116
|
call_api("upload", options) do
|
155
117
|
params = build_upload_params(options)
|
156
|
-
|
157
|
-
params[:file] = File.open(file, "rb")
|
158
|
-
else
|
159
|
-
params[:file] = file
|
160
|
-
end
|
118
|
+
params[:file] = Cloudinary::Utils.handle_file_param(file, options)
|
161
119
|
[params, [:file]]
|
162
120
|
end
|
163
121
|
end
|
@@ -406,29 +364,39 @@ class Cloudinary::Uploader
|
|
406
364
|
params[:signature] = Cloudinary::Utils.api_sign_request(params.reject { |k, v| non_signable.include?(k) }, api_secret, signature_algorithm)
|
407
365
|
params[:api_key] = api_key
|
408
366
|
end
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
if
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
367
|
+
|
368
|
+
api_url = Cloudinary::Utils.cloudinary_api_url(action, options)
|
369
|
+
api_proxy = options[:api_proxy] || Cloudinary.config.api_proxy
|
370
|
+
timeout = options.fetch(:timeout) { Cloudinary.config.to_h.fetch(:timeout, 60) }
|
371
|
+
|
372
|
+
conn = Faraday.new(url: api_url) do |faraday|
|
373
|
+
faraday.proxy = api_proxy if api_proxy
|
374
|
+
faraday.request :multipart, **options
|
375
|
+
faraday.request :url_encoded
|
376
|
+
faraday.adapter @adapter || Faraday.default_adapter
|
377
|
+
end
|
378
|
+
|
379
|
+
response = conn.send(:post) do |req|
|
380
|
+
req.headers = headers
|
381
|
+
req.body = params.reject { |_, v| v.nil? || v=="" }
|
382
|
+
req.options.timeout = timeout if timeout
|
383
|
+
end
|
384
|
+
|
385
|
+
raise CloudinaryException, "Server returned unexpected status code - #{response.status} - #{response.body}" unless [200, 400, 401, 403, 404, 500].include?(response.status)
|
386
|
+
begin
|
387
|
+
result = Cloudinary::Utils.json_decode(response.body)
|
388
|
+
rescue => e
|
389
|
+
# Error is parsing json
|
390
|
+
raise CloudinaryException, "Error parsing server response (#{response.status}) - #{response.body}. Got - #{e}"
|
391
|
+
end
|
392
|
+
if result["error"]
|
393
|
+
if return_error
|
394
|
+
result["error"]["http_code"] = response.status
|
395
|
+
else
|
396
|
+
raise CloudinaryException, result["error"]["message"]
|
430
397
|
end
|
431
398
|
end
|
399
|
+
|
432
400
|
if use_cache && !result.nil?
|
433
401
|
cache_results(result)
|
434
402
|
end
|