cloudinary 1.1.1 → 1.1.2

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
  SHA1:
3
- metadata.gz: ffc7266645b3ced1d9e812359e5465c092a5d235
4
- data.tar.gz: c88363381e77a8b0d564ff5166de4f3dce2d719a
3
+ metadata.gz: 0434852c7adc610fb1cf86057bff3e1e4691bae2
4
+ data.tar.gz: c930430f7658ebba0eb73fc97496d2aaaff84892
5
5
  SHA512:
6
- metadata.gz: b0260293a3726a9e27105b5175cc6f9502e85e15c55e20f8d8fe128cff3a0401ce74dc2301d03184cf0494635a6ac30c47b85257806f713a21b48f7232de1e85
7
- data.tar.gz: ebd11eb3dd9abe5f2e0c9ec30360c455a758d2bc4b0084989ed68d3d6af4cb0804b4d3725e38b92388b8d733560edc928e8326dd9afc5c5ce35821ef3e08bed5
6
+ metadata.gz: f912c8645358d41d2b69f0ddfde69915e98cfe0221a3f8ce583b83d3f2d936416c23a31f8c3951ec1776a051e13cc04a44d6500034ca8641d5d50b2e4e0bf76d
7
+ data.tar.gz: 19d6c8c6f0bde05cabbb57565a66eb0fb70a8648daa959c2602c7d012ece530af032fdb012669b1f7f8da78e70f8c69189ce17e2f5033be327d271e06d354749
@@ -1,4 +1,36 @@
1
1
 
2
+ 1.1.2 / 2015-12-16
3
+ ==================
4
+
5
+ * Support new archive (ZIP) creation API:
6
+ * Uploader: `create_archive`, `create_zip`.
7
+ * Utils: `download_archive_url`, `download_zip_url`
8
+ * Helper: `cl_download_archive_url`, `cl_download_zip_url`.
9
+ * Use basic to_query implementation when Rails is not available.
10
+ * Allow chained transformations and eager transformations to process width & height when crop is not defined.
11
+ * Apply style and whitespaces.
12
+ * Remove redundant variable. Replace if ! with until.
13
+ * Apply style and whitespaces.
14
+ * Remove redundant variable
15
+ * Add `:invalidate` option to `Cloudinary::Uploader.rename`
16
+ * Add line spacing to text layer
17
+ * Add upload mapping
18
+ * Add `Cloudinary::Api.restore`
19
+ * Add `deep_hash_values` matcher. Add `invalidate` test to `explicit`
20
+ * Add `Cloudinary.user_platform`
21
+ * Merge branch 'feature/breakpoints_and_zip'
22
+ * Add test for `Cloudinary::Uploader.create_zip`
23
+ * Refactor `create_archive`. Rename `generate_zip_download_url`. Create `download_archive_url`. Add cleanup to spec code.
24
+ * Add condition to `image_tag` and `image_path` aliasing.
25
+ * Add `archive_spec.rb`. Add rubyzip development dependency.
26
+ * Add `Cloudinary::` to `Utils` calls
27
+ * Fix temp file name in spec. Re-enable deletion of resources after the test.
28
+ * Add deprecation warning to `zip_download_url`
29
+ * Fix rake `build` dependency to `cloudinary:fetch_assets`
30
+ * Apply `symbolize_keys`
31
+ * Support the aspect_ratio transformation parameter
32
+ * Support responsive_breakpoints JSON parameter in upload and explicit API
33
+
2
34
  1.1.1 / 2015-12-04
3
35
  ==================
4
36
 
@@ -23,6 +23,7 @@ Gem::Specification.new do |s|
23
23
  s.add_dependency "aws_cf_signer"
24
24
  s.add_development_dependency "rspec", '>=3.2'
25
25
  s.add_development_dependency "rspec-rails"
26
+ s.add_development_dependency "rubyzip"
26
27
 
27
28
  if RUBY_VERSION > "1.9"
28
29
  s.add_dependency "rest-client"
@@ -23,8 +23,27 @@ module Cloudinary
23
23
  OLD_AKAMAI_SHARED_CDN = "cloudinary-a.akamaihd.net"
24
24
  SHARED_CDN = AKAMAI_SHARED_CDN
25
25
 
26
- USER_AGENT = "cld-ruby-" + VERSION
27
-
26
+ USER_AGENT = "CloudinaryRuby/" + VERSION
27
+ @@user_platform = ""
28
+
29
+ # Add platform information to the USER_AGENT header
30
+ # This is intended for platform information and not individual applications!
31
+ def self.user_platform=(value)
32
+ @@user_platform= value
33
+ end
34
+
35
+ def self.user_platform
36
+ @@user_platform
37
+ end
38
+
39
+ def self.USER_AGENT
40
+ if @@user_platform.empty?
41
+ "#{USER_AGENT}"
42
+ else
43
+ "#{@@user_platform} #{USER_AGENT}"
44
+ end
45
+ end
46
+
28
47
  FORMAT_ALIASES = {
29
48
  "jpeg" => "jpg",
30
49
  "jpe" => "jpg",
@@ -8,165 +8,173 @@ class Cloudinary::Api
8
8
  class RateLimited < Error; end
9
9
  class BadRequest < Error; end
10
10
  class GeneralError < Error; end
11
- class AuthorizationRequired < Error; end
11
+ class AuthorizationRequired < Error; end
12
12
  class Response < Hash
13
13
  attr_reader :rate_limit_reset_at, :rate_limit_remaining, :rate_limit_allowed
14
+
14
15
  def initialize(response)
15
16
  self.update(Cloudinary::Api.send(:parse_json_response, response))
16
- @rate_limit_allowed = response.headers[:x_featureratelimit_limit].to_i
17
- @rate_limit_reset_at = Time.parse(response.headers[:x_featureratelimit_reset])
18
- @rate_limit_remaining = response.headers[:x_featureratelimit_remaining].to_i
17
+ @rate_limit_allowed = response.headers[:x_featureratelimit_limit].to_i
18
+ @rate_limit_reset_at = Time.parse(response.headers[:x_featureratelimit_reset])
19
+ @rate_limit_remaining = response.headers[:x_featureratelimit_remaining].to_i
19
20
  end
20
21
  end
21
22
 
22
23
  def self.ping(options={})
23
24
  call_api(:get, "ping", {}, options)
24
25
  end
25
-
26
+
26
27
  def self.usage(options={})
27
28
  call_api(:get, "usage", {}, options)
28
29
  end
29
-
30
+
30
31
  def self.resource_types(options={})
31
32
  call_api(:get, "resources", {}, options)
32
33
  end
33
34
 
34
35
  def self.resources(options={})
35
36
  resource_type = options[:resource_type] || "image"
36
- type = options[:type]
37
- uri = "resources/#{resource_type}"
38
- uri += "/#{type}" if !type.blank?
39
- call_api(:get, uri, only(options, :next_cursor, :max_results, :prefix, :tags, :context, :moderations, :direction, :start_at), options)
37
+ type = options[:type]
38
+ uri = "resources/#{resource_type}"
39
+ uri += "/#{type}" unless type.blank?
40
+ call_api(:get, uri, only(options, :next_cursor, :max_results, :prefix, :tags, :context, :moderations, :direction, :start_at), options)
40
41
  end
41
-
42
+
42
43
  def self.resources_by_tag(tag, options={})
43
44
  resource_type = options[:resource_type] || "image"
44
- uri = "resources/#{resource_type}/tags/#{tag}"
45
- call_api(:get, uri, only(options, :next_cursor, :max_results, :tags, :context, :moderations, :direction), options)
45
+ uri = "resources/#{resource_type}/tags/#{tag}"
46
+ call_api(:get, uri, only(options, :next_cursor, :max_results, :tags, :context, :moderations, :direction), options)
46
47
  end
47
-
48
+
48
49
  def self.resources_by_moderation(kind, status, options={})
49
50
  resource_type = options[:resource_type] || "image"
50
- uri = "resources/#{resource_type}/moderations/#{kind}/#{status}"
51
- call_api(:get, uri, only(options, :next_cursor, :max_results, :tags, :context, :moderations, :direction), options)
51
+ uri = "resources/#{resource_type}/moderations/#{kind}/#{status}"
52
+ call_api(:get, uri, only(options, :next_cursor, :max_results, :tags, :context, :moderations, :direction), options)
52
53
  end
53
-
54
+
54
55
  def self.resources_by_ids(public_ids, options={})
55
56
  resource_type = options[:resource_type] || "image"
56
- type = options[:type] || "upload"
57
- uri = "resources/#{resource_type}/#{type}"
57
+ type = options[:type] || "upload"
58
+ uri = "resources/#{resource_type}/#{type}"
58
59
  call_api(:get, uri, only(options, :tags, :context, :moderations).merge(:public_ids => public_ids), options)
59
60
  end
60
-
61
+
61
62
  def self.resource(public_id, options={})
62
63
  resource_type = options[:resource_type] || "image"
63
- type = options[:type] || "upload"
64
- uri = "resources/#{resource_type}/#{type}/#{public_id}"
65
- call_api(:get, uri, only(options, :colors, :exif, :faces, :image_metadata, :pages, :phash, :coordinates, :max_results), options)
64
+ type = options[:type] || "upload"
65
+ uri = "resources/#{resource_type}/#{type}/#{public_id}"
66
+ call_api(:get, uri, only(options, :colors, :exif, :faces, :image_metadata, :pages, :phash, :coordinates, :max_results), options)
66
67
  end
67
-
68
- def self.update(public_id, options={})
68
+
69
+ def self.restore(public_ids, options={})
69
70
  resource_type = options[:resource_type] || "image"
70
- type = options[:type] || "upload"
71
- uri = "resources/#{resource_type}/#{type}/#{public_id}"
71
+ type = options[:type] || "upload"
72
+ uri = "resources/#{resource_type}/#{type}/restore"
73
+ call_api(:post, uri, { :public_ids => public_ids }, options)
74
+ end
75
+
76
+ def self.update(public_id, options={})
77
+ resource_type = options[:resource_type] || "image"
78
+ type = options[:type] || "upload"
79
+ uri = "resources/#{resource_type}/#{type}/#{public_id}"
72
80
  update_options = {
73
- :tags => options[:tags] && Cloudinary::Utils.build_array(options[:tags]).join(","),
74
- :context => Cloudinary::Utils.encode_hash(options[:context]),
75
- :face_coordinates => Cloudinary::Utils.encode_double_array(options[:face_coordinates]),
81
+ :tags => options[:tags] && Cloudinary::Utils.build_array(options[:tags]).join(","),
82
+ :context => Cloudinary::Utils.encode_hash(options[:context]),
83
+ :face_coordinates => Cloudinary::Utils.encode_double_array(options[:face_coordinates]),
76
84
  :custom_coordinates => Cloudinary::Utils.encode_double_array(options[:custom_coordinates]),
77
- :moderation_status => options[:moderation_status],
78
- :raw_convert => options[:raw_convert],
79
- :ocr => options[:ocr],
80
- :categorization => options[:categorization],
81
- :detection => options[:detection],
82
- :similarity_search => options[:similarity_search],
85
+ :moderation_status => options[:moderation_status],
86
+ :raw_convert => options[:raw_convert],
87
+ :ocr => options[:ocr],
88
+ :categorization => options[:categorization],
89
+ :detection => options[:detection],
90
+ :similarity_search => options[:similarity_search],
83
91
  :background_removal => options[:background_removal],
84
- :auto_tagging => options[:auto_tagging] && options[:auto_tagging].to_f
92
+ :auto_tagging => options[:auto_tagging] && options[:auto_tagging].to_f
85
93
  }
86
94
  call_api(:post, uri, update_options, options)
87
95
  end
88
-
96
+
89
97
  def self.delete_resources(public_ids, options={})
90
98
  resource_type = options[:resource_type] || "image"
91
- type = options[:type] || "upload"
92
- uri = "resources/#{resource_type}/#{type}"
93
- call_api(:delete, uri, {:public_ids=>public_ids}.merge(only(options, :keep_original, :invalidate)), options)
99
+ type = options[:type] || "upload"
100
+ uri = "resources/#{resource_type}/#{type}"
101
+ call_api(:delete, uri, { :public_ids => public_ids }.merge(only(options, :keep_original, :invalidate)), options)
94
102
  end
95
103
 
96
104
  def self.delete_resources_by_prefix(prefix, options={})
97
105
  resource_type = options[:resource_type] || "image"
98
- type = options[:type] || "upload"
99
- uri = "resources/#{resource_type}/#{type}"
100
- call_api(:delete, uri, {:prefix=>prefix}.merge(only(options, :keep_original, :next_cursor, :invalidate)), options)
106
+ type = options[:type] || "upload"
107
+ uri = "resources/#{resource_type}/#{type}"
108
+ call_api(:delete, uri, { :prefix => prefix }.merge(only(options, :keep_original, :next_cursor, :invalidate)), options)
101
109
  end
102
-
110
+
103
111
  def self.delete_all_resources(options={})
104
112
  resource_type = options[:resource_type] || "image"
105
- type = options[:type] || "upload"
106
- uri = "resources/#{resource_type}/#{type}"
107
- call_api(:delete, uri, {:all=>true}.merge(only(options, :keep_original, :next_cursor, :invalidate)), options)
113
+ type = options[:type] || "upload"
114
+ uri = "resources/#{resource_type}/#{type}"
115
+ call_api(:delete, uri, { :all => true }.merge(only(options, :keep_original, :next_cursor, :invalidate)), options)
108
116
  end
109
-
117
+
110
118
  def self.delete_resources_by_tag(tag, options={})
111
119
  resource_type = options[:resource_type] || "image"
112
- uri = "resources/#{resource_type}/tags/#{tag}"
113
- call_api(:delete, uri, only(options, :keep_original, :next_cursor, :invalidate), options)
120
+ uri = "resources/#{resource_type}/tags/#{tag}"
121
+ call_api(:delete, uri, only(options, :keep_original, :next_cursor, :invalidate), options)
114
122
  end
115
-
123
+
116
124
  def self.delete_derived_resources(derived_resource_ids, options={})
117
125
  uri = "derived_resources"
118
- call_api(:delete, uri, {:derived_resource_ids=>derived_resource_ids}, options)
126
+ call_api(:delete, uri, { :derived_resource_ids => derived_resource_ids }, options)
119
127
  end
120
128
 
121
129
  def self.tags(options={})
122
130
  resource_type = options[:resource_type] || "image"
123
- uri = "tags/#{resource_type}"
124
- call_api(:get, uri, only(options, :next_cursor, :max_results, :prefix), options)
131
+ uri = "tags/#{resource_type}"
132
+ call_api(:get, uri, only(options, :next_cursor, :max_results, :prefix), options)
125
133
  end
126
-
134
+
127
135
  def self.transformations(options={})
128
- call_api(:get, "transformations", only(options, :next_cursor, :max_results), options)
136
+ call_api(:get, "transformations", only(options, :next_cursor, :max_results), options)
129
137
  end
130
138
 
131
139
  def self.transformation(transformation, options={})
132
- call_api(:get, "transformations/#{transformation_string(transformation)}", only(options, :max_results), options)
140
+ call_api(:get, "transformations/#{transformation_string(transformation)}", only(options, :max_results), options)
133
141
  end
134
-
142
+
135
143
  def self.delete_transformation(transformation, options={})
136
- call_api(:delete, "transformations/#{transformation_string(transformation)}", {}, options)
144
+ call_api(:delete, "transformations/#{transformation_string(transformation)}", {}, options)
137
145
  end
138
-
146
+
139
147
  # updates - supports:
140
148
  # "allowed_for_strict" boolean
141
149
  # "unsafe_update" transformation params - updates a named transformation parameters without regenerating existing images
142
150
  def self.update_transformation(transformation, updates, options={})
143
- params = only(updates, :allowed_for_strict)
151
+ params = only(updates, :allowed_for_strict)
144
152
  params[:unsafe_update] = transformation_string(updates[:unsafe_update]) if updates[:unsafe_update]
145
153
  call_api(:put, "transformations/#{transformation_string(transformation)}", params, options)
146
154
  end
147
-
155
+
148
156
  def self.create_transformation(name, definition, options={})
149
- call_api(:post, "transformations/#{name}", {:transformation=>transformation_string(definition)}, options)
157
+ call_api(:post, "transformations/#{name}", { :transformation => transformation_string(definition) }, options)
150
158
  end
151
-
159
+
152
160
  # upload presets
153
161
  def self.upload_presets(options={})
154
- call_api(:get, "upload_presets", only(options, :next_cursor, :max_results), options)
162
+ call_api(:get, "upload_presets", only(options, :next_cursor, :max_results), options)
155
163
  end
156
164
 
157
165
  def self.upload_preset(name, options={})
158
166
  call_api(:get, "upload_presets/#{name}", only(options, :max_results), options)
159
167
  end
160
-
168
+
161
169
  def self.delete_upload_preset(name, options={})
162
- call_api(:delete, "upload_presets/#{name}", {}, options)
170
+ call_api(:delete, "upload_presets/#{name}", {}, options)
163
171
  end
164
-
172
+
165
173
  def self.update_upload_preset(name, options={})
166
174
  params = Cloudinary::Uploader.build_upload_params(options)
167
175
  call_api(:put, "upload_presets/#{name}", params.merge(only(options, :unsigned, :disallow_public_id)), options)
168
176
  end
169
-
177
+
170
178
  def self.create_upload_preset(options={})
171
179
  params = Cloudinary::Uploader.build_upload_params(options)
172
180
  call_api(:post, "upload_presets", params.merge(only(options, :name, :unsigned, :disallow_public_id)), options)
@@ -179,55 +187,79 @@ class Cloudinary::Api
179
187
  def self.subfolders(of_folder_path, options={})
180
188
  call_api(:get, "folders/#{of_folder_path}", {}, options)
181
189
  end
182
-
190
+
191
+ def self.upload_mappings(options={})
192
+ params = only(options, :next_cursor, :max_results)
193
+ call_api(:get, :upload_mappings, params, options)
194
+ end
195
+
196
+ def self.upload_mapping(name=nil, options={})
197
+ call_api(:get, 'upload_mappings', { :folder => name }, options)
198
+ end
199
+
200
+ def self.delete_upload_mapping(name, options={})
201
+ call_api(:delete, 'upload_mappings', { :folder => name }, options)
202
+ end
203
+
204
+ def self.update_upload_mapping(name, options={})
205
+ params = only(options, :template)
206
+ params[:folder] = name
207
+ call_api(:put, 'upload_mappings', params, options)
208
+ end
209
+
210
+ def self.create_upload_mapping(name, options={})
211
+ params = only(options, :template)
212
+ params[:folder] = name
213
+ call_api(:post, 'upload_mappings', params, options)
214
+ end
215
+
183
216
  protected
184
-
217
+
185
218
  def self.call_api(method, uri, params, options)
186
219
  cloudinary = options[:upload_prefix] || Cloudinary.config.upload_prefix || "https://api.cloudinary.com"
187
220
  cloud_name = options[:cloud_name] || Cloudinary.config.cloud_name || raise("Must supply cloud_name")
188
- api_key = options[:api_key] || Cloudinary.config.api_key || raise("Must supply api_key")
221
+ api_key = options[:api_key] || Cloudinary.config.api_key || raise("Must supply api_key")
189
222
  api_secret = options[:api_secret] || Cloudinary.config.api_secret || raise("Must supply api_secret")
190
- timeout = options[:timeout] || Cloudinary.config.timeout || 60
191
- api_url = [cloudinary, "v1_1", cloud_name, uri].join("/")
223
+ timeout = options[:timeout] || Cloudinary.config.timeout || 60
224
+ api_url = [cloudinary, "v1_1", cloud_name, uri].join("/")
192
225
  # Add authentication
193
226
  api_url.sub!(%r(^(https?://)), "\\1#{api_key}:#{api_secret}@")
194
-
195
- RestClient::Request.execute(:method => method, :url => api_url, :payload => params.reject{|k, v| v.nil? || v==""}, :timeout=> timeout, :headers => {"User-Agent" => Cloudinary::USER_AGENT}) do
196
- |response, request, tmpresult|
227
+
228
+ RestClient::Request.execute(:method => method, :url => api_url, :payload => params.reject { |k, v| v.nil? || v=="" }, :timeout => timeout, :headers => { "User-Agent" => Cloudinary::USER_AGENT }) do
229
+ |response, request, tmpresult|
197
230
  return Response.new(response) if response.code == 200
198
231
  exception_class = case response.code
199
- when 400 then BadRequest
200
- when 401 then AuthorizationRequired
201
- when 403 then NotAllowed
202
- when 404 then NotFound
203
- when 409 then AlreadyExists
204
- when 420 then RateLimited
205
- when 500 then GeneralError
206
- else raise GeneralError.new("Server returned unexpected status code - #{response.code} - #{response.body}")
232
+ when 400 then BadRequest
233
+ when 401 then AuthorizationRequired
234
+ when 403 then NotAllowed
235
+ when 404 then NotFound
236
+ when 409 then AlreadyExists
237
+ when 420 then RateLimited
238
+ when 500 then GeneralError
239
+ else raise GeneralError.new("Server returned unexpected status code - #{response.code} - #{response.body}")
207
240
  end
208
241
  json = parse_json_response(response)
209
242
  raise exception_class.new(json["error"]["message"])
210
- end
243
+ end
211
244
  end
212
-
245
+
213
246
  def self.parse_json_response(response)
214
247
  return Cloudinary::Utils.json_decode(response.body)
215
248
  rescue => e
216
249
  # Error is parsing json
217
250
  raise GeneralError.new("Error parsing server response (#{response.code}) - #{response.body}. Got - #{e}")
218
251
  end
219
-
252
+
220
253
  def self.only(hash, *keys)
221
254
  result = {}
222
- keys.each do
223
- |key|
255
+ keys.each do |key|
224
256
  result[key] = hash[key] if hash.include?(key)
225
257
  result[key] = hash[key.to_s] if hash.include?(key.to_s)
226
258
  end
227
259
  result
228
- end
229
-
260
+ end
261
+
230
262
  def self.transformation_string(transformation)
231
- transformation = transformation.is_a?(String) ? transformation : Cloudinary::Utils.generate_transformation_string(transformation.clone)
263
+ transformation.is_a?(String) ? transformation : Cloudinary::Utils.generate_transformation_string(transformation.clone)
232
264
  end
233
265
  end
@@ -236,10 +236,23 @@ module CloudinaryHelper
236
236
  Cloudinary::Utils.private_download_url(public_id, format, options)
237
237
  end
238
238
 
239
+ # Helper method that uses the deprecated ZIP download API.
240
+ # Replaced by cl_download_zip_url that uses the more advanced and robust archive generation and download API
241
+ # @deprecated
239
242
  def cl_zip_download_url(tag, options = {})
240
243
  Cloudinary::Utils.zip_download_url(tag, options)
241
244
  end
242
245
 
246
+ # @see {Cloudinary::Utils.download_archive_url}
247
+ def cl_download_archive_url(options = {})
248
+ Cloudinary::Utils.download_archive_url(options)
249
+ end
250
+
251
+ # @see {Cloudinary::Utils.download_zip_url}
252
+ def cl_download_zip_url(options = {})
253
+ Cloudinary::Utils.download_zip_url(options)
254
+ end
255
+
243
256
  def cl_signed_download_url(public_id, options = {})
244
257
  Cloudinary::Utils.signed_download_url(public_id, options)
245
258
  end
@@ -251,11 +264,11 @@ module CloudinaryHelper
251
264
  include ActionView::Helpers::AssetTagHelper
252
265
  end
253
266
  if defined?(::Rails::VERSION::MAJOR) && ::Rails::VERSION::MAJOR > 2 && Cloudinary.config.enhance_image_tag
254
- alias_method_chain :image_tag, :cloudinary # defines image_tag_without_cloudinary
255
- alias_method_chain :image_path, :cloudinary # defines image_path_without_cloudinary
267
+ alias_method_chain :image_tag, :cloudinary unless public_method_defined? :image_tag_without_cloudinary
268
+ alias_method_chain :image_path, :cloudinary unless public_method_defined? :image_path_without_cloudinary
256
269
  else
257
- alias_method :image_tag_without_cloudinary, :image_tag
258
- alias_method :image_path_without_cloudinary, :image_path
270
+ alias_method :image_tag_without_cloudinary, :image_tag unless public_method_defined? :image_tag_without_cloudinary
271
+ alias_method :image_path_without_cloudinary, :image_path unless public_method_defined? :image_path_without_cloudinary
259
272
  end
260
273
  end
261
274
  end