cloudinary 1.1.1 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,117 +3,135 @@ require 'rest_client'
3
3
  require 'json'
4
4
 
5
5
  class Cloudinary::Uploader
6
-
6
+
7
+ # @deprecated use {Cloudinary::Utils.build_eager} instead
7
8
  def self.build_eager(eager)
8
- return nil if eager.nil?
9
- Cloudinary::Utils.build_array(eager).map do
10
- |transformation, format|
11
- transformation = transformation.clone
12
- format = transformation.delete(:format) || format
13
- [Cloudinary::Utils.generate_transformation_string(transformation), format].compact.join("/")
14
- end.join("|")
9
+ Cloudinary::Utils.build_eager(eager)
15
10
  end
16
-
11
+
12
+ # @private
17
13
  def self.build_upload_params(options)
18
14
  #symbolize keys
19
15
  options = options.clone
20
- options.keys.each{|key| options[key.to_sym] = options.delete(key) if key.is_a?(String)}
21
-
22
- params = {:timestamp=>(options[:timestamp] || Time.now.to_i),
23
- :transformation => Cloudinary::Utils.generate_transformation_string(options.clone),
24
- :public_id=>options[:public_id],
25
- :callback=>options[:callback],
26
- :format=>options[:format],
27
- :type=>options[:type],
28
- :backup=>Cloudinary::Utils.as_safe_bool(options[:backup]),
29
- :faces=>Cloudinary::Utils.as_safe_bool(options[:faces]),
30
- :exif=>Cloudinary::Utils.as_safe_bool(options[:exif]),
31
- :colors=>Cloudinary::Utils.as_safe_bool(options[:colors]),
32
- :image_metadata=>Cloudinary::Utils.as_safe_bool(options[:image_metadata]),
33
- :invalidate=>Cloudinary::Utils.as_safe_bool(options[:invalidate]),
34
- :eager=>build_eager(options[:eager]),
35
- :headers=>build_custom_headers(options[:headers]),
36
- :use_filename=>Cloudinary::Utils.as_safe_bool(options[:use_filename]),
37
- :unique_filename=>Cloudinary::Utils.as_safe_bool(options[:unique_filename]),
38
- :overwrite=>Cloudinary::Utils.as_safe_bool(options[:overwrite]),
39
- :discard_original_filename=>Cloudinary::Utils.as_safe_bool(options[:discard_original_filename]),
40
- :notification_url=>options[:notification_url],
41
- :eager_notification_url=>options[:eager_notification_url],
42
- :eager_async=>Cloudinary::Utils.as_safe_bool(options[:eager_async]),
43
- :proxy=>options[:proxy],
44
- :folder=>options[:folder],
45
- :allowed_formats => Cloudinary::Utils.build_array(options[:allowed_formats]).join(","),
46
- :tags=>options[:tags] && Cloudinary::Utils.build_array(options[:tags]).join(","),
47
- :context => Cloudinary::Utils.encode_hash(options[:context]),
48
- :face_coordinates => Cloudinary::Utils.encode_double_array(options[:face_coordinates]),
49
- :custom_coordinates => Cloudinary::Utils.encode_double_array(options[:custom_coordinates]),
50
- :moderation => options[:moderation],
51
- :raw_convert => options[:raw_convert],
52
- :ocr => options[:ocr],
53
- :categorization => options[:categorization],
54
- :detection => options[:detection],
55
- :similarity_search => options[:similarity_search],
56
- :background_removal => options[:background_removal],
57
- :auto_tagging => options[:auto_tagging] && options[:auto_tagging].to_f,
58
- :upload_preset => options[:upload_preset],
59
- :phash => Cloudinary::Utils.as_safe_bool(options[:phash]),
60
- :return_delete_token => Cloudinary::Utils.as_safe_bool(options[:return_delete_token]),
61
- }
62
- params
16
+ options.keys.each { |key| options[key.to_sym] = options.delete(key) if key.is_a?(String) }
17
+
18
+ params = {
19
+ :allowed_formats => Cloudinary::Utils.build_array(options[:allowed_formats]).join(","),
20
+ :auto_tagging => options[:auto_tagging] && options[:auto_tagging].to_f,
21
+ :background_removal => options[:background_removal],
22
+ :backup => Cloudinary::Utils.as_safe_bool(options[:backup]),
23
+ :callback => options[:callback],
24
+ :categorization => options[:categorization],
25
+ :colors => Cloudinary::Utils.as_safe_bool(options[:colors]),
26
+ :context => Cloudinary::Utils.encode_hash(options[:context]),
27
+ :custom_coordinates => Cloudinary::Utils.encode_double_array(options[:custom_coordinates]),
28
+ :detection => options[:detection],
29
+ :discard_original_filename => Cloudinary::Utils.as_safe_bool(options[:discard_original_filename]),
30
+ :eager => Cloudinary::Utils.build_eager(options[:eager]),
31
+ :eager_async => Cloudinary::Utils.as_safe_bool(options[:eager_async]),
32
+ :eager_notification_url => options[:eager_notification_url],
33
+ :exif => Cloudinary::Utils.as_safe_bool(options[:exif]),
34
+ :face_coordinates => Cloudinary::Utils.encode_double_array(options[:face_coordinates]),
35
+ :faces => Cloudinary::Utils.as_safe_bool(options[:faces]),
36
+ :folder => options[:folder],
37
+ :format => options[:format],
38
+ :headers => build_custom_headers(options[:headers]),
39
+ :image_metadata => Cloudinary::Utils.as_safe_bool(options[:image_metadata]),
40
+ :invalidate => Cloudinary::Utils.as_safe_bool(options[:invalidate]),
41
+ :moderation => options[:moderation],
42
+ :notification_url => options[:notification_url],
43
+ :ocr => options[:ocr],
44
+ :overwrite => Cloudinary::Utils.as_safe_bool(options[:overwrite]),
45
+ :phash => Cloudinary::Utils.as_safe_bool(options[:phash]),
46
+ :proxy => options[:proxy],
47
+ :public_id => options[:public_id],
48
+ :raw_convert => options[:raw_convert],
49
+ :responsive_breakpoints => Cloudinary::Utils.generate_responsive_breakpoints_string(options[:responsive_breakpoints]),
50
+ :return_delete_token => Cloudinary::Utils.as_safe_bool(options[:return_delete_token]),
51
+ :similarity_search => options[:similarity_search],
52
+ :tags => options[:tags] && Cloudinary::Utils.build_array(options[:tags]).join(","),
53
+ :timestamp => (options[:timestamp] || Time.now.to_i),
54
+ :transformation => Cloudinary::Utils.generate_transformation_string(options.clone),
55
+ :type => options[:type],
56
+ :unique_filename => Cloudinary::Utils.as_safe_bool(options[:unique_filename]),
57
+ :upload_preset => options[:upload_preset],
58
+ :use_filename => Cloudinary::Utils.as_safe_bool(options[:use_filename]),
59
+ }
60
+ params
63
61
  end
64
-
62
+
63
+ # @private
64
+ def self.build_explicit_api_params(public_id, options = {})
65
+ options = Cloudinary::Utils.symbolize_keys options
66
+ params = {
67
+ :callback => options[:callback],
68
+ :eager => Cloudinary::Utils.build_eager(options[:eager]),
69
+ :eager_async => Cloudinary::Utils.as_safe_bool(options[:eager_async]),
70
+ :eager_notification_url => options[:eager_notification_url],
71
+ :face_coordinates => options[:face_coordinates] && Cloudinary::Utils.encode_double_array(options[:face_coordinates]),
72
+ :headers => build_custom_headers(options[:headers]),
73
+ :invalidate => Cloudinary::Utils.as_safe_bool(options[:invalidate]),
74
+ :public_id => public_id,
75
+ :responsive_breakpoints => Cloudinary::Utils.generate_responsive_breakpoints_string(options[:responsive_breakpoints]),
76
+ :tags => options[:tags] && Cloudinary::Utils.build_array(options[:tags]).join(","),
77
+ :timestamp => (options[:timestamp] || Time.now.to_i),
78
+ :type => options[:type]
79
+ }
80
+ params
81
+ end
82
+
65
83
  def self.unsigned_upload(file, upload_preset, options={})
66
84
  upload(file, options.merge(:unsigned => true, :upload_preset => upload_preset))
67
85
  end
68
-
86
+
69
87
  def self.upload(file, options={})
70
- call_api("upload", options) do
88
+ call_api("upload", options) do
71
89
  params = build_upload_params(options)
72
90
  if file.is_a?(Pathname)
73
91
  params[:file] = File.open(file, "rb")
74
92
  elsif file.respond_to?(:read) || file =~ /^ftp:|^https?:|^s3:|^data:[^;]*;base64,([a-zA-Z0-9\/+\n=]+)$/
75
93
  params[:file] = file
76
- else
94
+ else
77
95
  params[:file] = File.open(file, "rb")
78
96
  end
79
97
  [params, [:file]]
80
- end
98
+ end
81
99
  end
82
100
 
83
101
  # Upload large files. Note that public_id should include an extension for best results.
84
102
  def self.upload_large(file, public_id_or_options={}, old_options={})
85
103
  if public_id_or_options.is_a?(Hash)
86
- options = public_id_or_options
104
+ options = public_id_or_options
87
105
  public_id = options[:public_id]
88
106
  else
89
107
  public_id = public_id_or_options
90
- options = old_options
91
- end
108
+ options = old_options
109
+ end
92
110
  if file.is_a?(Pathname) || !file.respond_to?(:read)
93
111
  filename = file
94
- file = File.open(file, "rb")
112
+ file = File.open(file, "rb")
95
113
  else
96
114
  filename = "cloudinaryfile"
97
115
  end
98
- upload = upload_id = nil
99
- index = 0
116
+ upload = nil
117
+ index = 0
100
118
  chunk_size = options[:chunk_size] || 20_000_000
101
- while !file.eof?
102
- buffer = file.read(chunk_size)
119
+ until file.eof?
120
+ buffer = file.read(chunk_size)
103
121
  current_loc = index*chunk_size
104
- range = "bytes #{current_loc}-#{current_loc+buffer.size - 1}/#{file.size}"
105
- upload = upload_large_part(Cloudinary::Blob.new(buffer, :original_filename=>filename), options.merge(:public_id=>public_id, :content_range=>range))
106
- public_id = upload["public_id"]
107
- index += 1
122
+ range = "bytes #{current_loc}-#{current_loc+buffer.size - 1}/#{file.size}"
123
+ upload = upload_large_part(Cloudinary::Blob.new(buffer, :original_filename => filename), options.merge(:public_id => public_id, :content_range => range))
124
+ public_id = upload["public_id"]
125
+ index += 1
108
126
  end
109
127
  upload
110
128
  end
111
-
129
+
112
130
 
113
131
  # Upload large files. Note that public_id should include an extension for best results.
114
132
  def self.upload_large_part(file, options={})
115
133
  options[:resource_type] ||= :raw
116
- call_api("upload", options) do
134
+ call_api("upload", options) do
117
135
  params = build_upload_params(options)
118
136
  if file.is_a?(Pathname) || !file.respond_to?(:read)
119
137
  params[:file] = File.open(file, "rb")
@@ -121,168 +139,173 @@ class Cloudinary::Uploader
121
139
  params[:file] = file
122
140
  end
123
141
  [params, [:file]]
124
- end
142
+ end
125
143
  end
126
144
 
127
145
  def self.destroy(public_id, options={})
128
- call_api("destroy", options) do
146
+ call_api("destroy", options) do
129
147
  {
130
- :timestamp=>(options[:timestamp] || Time.now.to_i),
131
- :type=>options[:type],
132
- :public_id=> public_id,
133
- :invalidate=>options[:invalidate],
148
+ :timestamp => (options[:timestamp] || Time.now.to_i),
149
+ :type => options[:type],
150
+ :public_id => public_id,
151
+ :invalidate => options[:invalidate],
134
152
  }
135
- end
153
+ end
136
154
  end
137
155
 
138
156
  def self.rename(from_public_id, to_public_id, options={})
139
- call_api("rename", options) do
157
+ call_api("rename", options) do
140
158
  {
141
- :timestamp=>(options[:timestamp] || Time.now.to_i),
142
- :type=>options[:type],
143
- :overwrite=>options[:overwrite],
144
- :from_public_id=>from_public_id,
145
- :to_public_id=>to_public_id,
159
+ :timestamp => (options[:timestamp] || Time.now.to_i),
160
+ :type => options[:type],
161
+ :overwrite => Cloudinary::Utils.as_safe_bool(options[:overwrite]),
162
+ :from_public_id => from_public_id,
163
+ :to_public_id => to_public_id,
164
+ :invalidate => Cloudinary::Utils.as_safe_bool(options[:invalidate])
146
165
  }
147
- end
166
+ end
148
167
  end
149
168
 
150
169
  def self.exists?(public_id, options={})
151
170
  cloudinary_url = Cloudinary::Utils.cloudinary_url(public_id, options)
152
171
  begin
153
- RestClient::Request.execute(:method => :head, :url => cloudinary_url, :timeout=>5).code.to_s =~ /2\d{2}/
154
- rescue RestClient::ResourceNotFound => e
172
+ RestClient::Request.execute(:method => :head, :url => cloudinary_url, :timeout => 5).code.to_s =~ /2\d{2}/
173
+ rescue RestClient::ResourceNotFound
155
174
  return false
156
175
  end
157
-
176
+
158
177
  end
159
178
 
160
179
  def self.explicit(public_id, options={})
161
- call_api("explicit", options) do
162
- {
163
- :timestamp=>(options[:timestamp] || Time.now.to_i),
164
- :type=>options[:type],
165
- :public_id=> public_id,
166
- :callback=> options[:callback],
167
- :eager=>build_eager(options[:eager]),
168
- :eager_notification_url=>options[:eager_notification_url],
169
- :eager_async=>Cloudinary::Utils.as_safe_bool(options[:eager_async]),
170
- :headers=>build_custom_headers(options[:headers]),
171
- :tags=>options[:tags] && Cloudinary::Utils.build_array(options[:tags]).join(","),
172
- :face_coordinates => options[:face_coordinates] && Cloudinary::Utils.encode_double_array(options[:face_coordinates])
173
- }
174
- end
180
+ call_api("explicit", options) do
181
+ self.build_explicit_api_params(public_id, options)
182
+ end
175
183
  end
176
-
177
- TEXT_PARAMS = [:public_id, :font_family, :font_size, :font_color, :text_align, :font_weight, :font_style, :background, :opacity, :text_decoration, :line_spacing]
184
+
185
+ # Creates a new archive in the server and returns information in JSON format
186
+ def self.create_archive(options={}, target_format = nil)
187
+ call_api("generate_archive", options) do
188
+ opt = Cloudinary::Utils.archive_params(options)
189
+ opt[:target_format] = target_format if target_format
190
+ opt
191
+ end
192
+ end
193
+
194
+ # Creates a new zip archive in the server and returns information in JSON format
195
+ def self.create_zip(options={})
196
+ create_archive(options, "zip")
197
+ end
198
+
199
+ TEXT_PARAMS = [:public_id, :font_family, :font_size, :font_color, :text_align, :font_weight, :font_style, :background, :opacity, :text_decoration, :line_spacing]
200
+
178
201
  def self.text(text, options={})
179
202
  call_api("text", options) do
180
- params = {:timestamp => Time.now.to_i, :text=>text}
181
- TEXT_PARAMS.each{|k| params[k] = options[k] if !options[k].nil?}
203
+ params = { :timestamp => Time.now.to_i, :text => text }
204
+ TEXT_PARAMS.each { |k| params[k] = options[k] unless options[k].nil? }
182
205
  params
183
206
  end
184
- end
185
-
207
+ end
208
+
186
209
  def self.generate_sprite(tag, options={})
187
210
  version_store = options.delete(:version_store)
188
-
211
+
189
212
  result = call_api("sprite", options) do
190
213
  {
191
- :timestamp=>(options[:timestamp] || Time.now.to_i),
192
- :tag=>tag,
193
- :async=>options[:async],
194
- :notification_url=>options[:notification_url],
195
- :transformation => Cloudinary::Utils.generate_transformation_string(options.merge(:fetch_format=>options[:format]))
196
- }
214
+ :timestamp => (options[:timestamp] || Time.now.to_i),
215
+ :tag => tag,
216
+ :async => options[:async],
217
+ :notification_url => options[:notification_url],
218
+ :transformation => Cloudinary::Utils.generate_transformation_string(options.merge(:fetch_format => options[:format]))
219
+ }
197
220
  end
198
-
221
+
199
222
  if version_store == :file && result && result["version"]
200
223
  if defined?(Rails) && defined?(Rails.root)
201
224
  FileUtils.mkdir_p("#{Rails.root}/tmp/cloudinary")
202
- File.open("#{Rails.root}/tmp/cloudinary/cloudinary_sprite_#{tag}.version", "w"){|file| file.print result["version"].to_s}
203
- end
204
- end
225
+ File.open("#{Rails.root}/tmp/cloudinary/cloudinary_sprite_#{tag}.version", "w") { |file| file.print result["version"].to_s }
226
+ end
227
+ end
205
228
  return result
206
229
  end
207
230
 
208
231
  def self.multi(tag, options={})
209
232
  call_api("multi", options) do
210
233
  {
211
- :timestamp=>(options[:timestamp] || Time.now.to_i),
212
- :tag=>tag,
213
- :format=>options[:format],
214
- :async=>options[:async],
215
- :notification_url=>options[:notification_url],
216
- :transformation => Cloudinary::Utils.generate_transformation_string(options.clone)
217
- }
234
+ :timestamp => (options[:timestamp] || Time.now.to_i),
235
+ :tag => tag,
236
+ :format => options[:format],
237
+ :async => options[:async],
238
+ :notification_url => options[:notification_url],
239
+ :transformation => Cloudinary::Utils.generate_transformation_string(options.clone)
240
+ }
218
241
  end
219
242
  end
220
-
221
- def self.explode(public_id, options={})
243
+
244
+ def self.explode(public_id, options={})
222
245
  call_api("explode", options) do
223
246
  {
224
- :timestamp=>(options[:timestamp] || Time.now.to_i),
225
- :public_id=>public_id,
226
- :type=>options[:type],
227
- :format=>options[:format],
228
- :notification_url=>options[:notification_url],
229
- :transformation => Cloudinary::Utils.generate_transformation_string(options.clone)
230
- }
247
+ :timestamp => (options[:timestamp] || Time.now.to_i),
248
+ :public_id => public_id,
249
+ :type => options[:type],
250
+ :format => options[:format],
251
+ :notification_url => options[:notification_url],
252
+ :transformation => Cloudinary::Utils.generate_transformation_string(options.clone)
253
+ }
231
254
  end
232
255
  end
233
-
256
+
234
257
  # options may include 'exclusive' (boolean) which causes clearing this tag from all other resources
235
258
  def self.add_tag(tag, public_ids = [], options = {})
236
259
  exclusive = options.delete(:exclusive)
237
- command = exclusive ? "set_exclusive" : "add"
238
- return self.call_tags_api(tag, command, public_ids, options)
260
+ command = exclusive ? "set_exclusive" : "add"
261
+ return self.call_tags_api(tag, command, public_ids, options)
239
262
  end
240
263
 
241
264
  def self.remove_tag(tag, public_ids = [], options = {})
242
- return self.call_tags_api(tag, "remove", public_ids, options)
265
+ return self.call_tags_api(tag, "remove", public_ids, options)
243
266
  end
244
267
 
245
268
  def self.replace_tag(tag, public_ids = [], options = {})
246
- return self.call_tags_api(tag, "replace", public_ids, options)
269
+ return self.call_tags_api(tag, "replace", public_ids, options)
247
270
  end
248
-
271
+
249
272
  private
250
-
273
+
251
274
  def self.call_tags_api(tag, command, public_ids = [], options = {})
252
275
  return call_api("tags", options) do
253
276
  {
254
- :timestamp=>(options[:timestamp] || Time.now.to_i),
255
- :tag=>tag,
277
+ :timestamp => (options[:timestamp] || Time.now.to_i),
278
+ :tag => tag,
256
279
  :public_ids => Cloudinary::Utils.build_array(public_ids),
257
- :command => command,
258
- :type => options[:type]
259
- }
260
- end
280
+ :command => command,
281
+ :type => options[:type]
282
+ }
283
+ end
261
284
  end
262
-
285
+
263
286
  def self.call_api(action, options)
264
- options = options.clone
287
+ options = options.clone
265
288
  return_error = options.delete(:return_error)
266
289
 
267
290
  params, non_signable = yield
268
- non_signable ||= []
269
-
291
+ non_signable ||= []
292
+
270
293
  unless options[:unsigned]
271
- api_key = options[:api_key] || Cloudinary.config.api_key || raise(CloudinaryException, "Must supply api_key")
272
- api_secret = options[:api_secret] || Cloudinary.config.api_secret || raise(CloudinaryException, "Must supply api_secret")
273
- params[:signature] = Cloudinary::Utils.api_sign_request(params.reject{|k,v| non_signable.include?(k)}, api_secret)
274
- params[:api_key] = api_key
294
+ api_key = options[:api_key] || Cloudinary.config.api_key || raise(CloudinaryException, "Must supply api_key")
295
+ api_secret = options[:api_secret] || Cloudinary.config.api_secret || raise(CloudinaryException, "Must supply api_secret")
296
+ params[:signature] = Cloudinary::Utils.api_sign_request(params.reject { |k, v| non_signable.include?(k) }, api_secret)
297
+ params[:api_key] = api_key
275
298
  end
276
299
  timeout = options[:timeout] || Cloudinary.config.timeout || 60
277
300
 
278
301
  result = nil
279
-
280
- api_url = Cloudinary::Utils.cloudinary_api_url(action, options)
281
- headers = {"User-Agent" => Cloudinary::USER_AGENT}
302
+
303
+ api_url = Cloudinary::Utils.cloudinary_api_url(action, options)
304
+ headers = { "User-Agent" => Cloudinary::USER_AGENT }
282
305
  headers['Content-Range'] = options[:content_range] if options[:content_range]
283
- RestClient::Request.execute(:method => :post, :url => api_url, :payload => params.reject{|k, v| v.nil? || v==""}, :timeout=> timeout, :headers => headers) do
284
- |response, request, tmpresult|
285
- raise CloudinaryException, "Server returned unexpected status code - #{response.code} - #{response.body}" if ![200,400,401,403,404,500].include?(response.code)
306
+ RestClient::Request.execute(:method => :post, :url => api_url, :payload => params.reject { |k, v| v.nil? || v=="" }, :timeout => timeout, :headers => headers) do
307
+ |response, request, tmpresult|
308
+ raise CloudinaryException, "Server returned unexpected status code - #{response.code} - #{response.body}" unless [200, 400, 401, 403, 404, 500].include?(response.code)
286
309
  begin
287
310
  result = Cloudinary::Utils.json_decode(response.body)
288
311
  rescue => e
@@ -295,13 +318,13 @@ class Cloudinary::Uploader
295
318
  else
296
319
  raise CloudinaryException, result["error"]["message"]
297
320
  end
298
- end
321
+ end
299
322
  end
300
-
301
- result
323
+
324
+ result
302
325
  end
303
-
326
+
304
327
  def self.build_custom_headers(headers)
305
- Array(headers).map{|*a| a.join(": ")}.join("\n")
328
+ Array(headers).map { |*a| a.join(": ") }.join("\n")
306
329
  end
307
330
  end