cloudinary 1.1.1 → 1.1.2

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 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