cloudinary 1.0.78 → 1.0.79

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: 1b465c67371871382525ab5dd84b4ac295ca59f9
4
- data.tar.gz: a46f2de133c16575112eaefb0c92955080f759a4
3
+ metadata.gz: b29c537f39a98d72f302907e0f50fbb8cafa1a10
4
+ data.tar.gz: b8a1adc7b8fe8f9bc154f909e44b4ef0a16387fc
5
5
  SHA512:
6
- metadata.gz: 21755db5865749be5a67c64ce750d8666618325d0f7d1b5713e0297aa02f30d40d20da5859896036aeb3f6f0312dd2c1b47b0b0cc5e539bd9333bf474653abbb
7
- data.tar.gz: a2b04439ffaae15f62100723b97a4ac52e0c543e07f5e2af3f5e644ac1957c962b7cadf522d932641915c9f2c960db8e1119e0db401126860f63dd8596c8ef2a
6
+ metadata.gz: 1fc90e873024c8b1f8f75abf0500684024b3fd5fee87086eecf078645466378bdc3a8fc7965f9c034b3567ff03d8a150f613692b1078110a4aa2721bde21dd79
7
+ data.tar.gz: 3edd3c23ec7e6053f03a0670e0910dbfddf9260e1ccfe411635c0749db175229eb6b4412b37e0d99591808be159686eea2b6068d407fbb0dccd3aac2a3d4c162
data/CHANGELOG CHANGED
@@ -1,3 +1,13 @@
1
+ = Version 1.0.79 - 2014-12-11
2
+ * Support folder listing API.
3
+ * Add support for conditional processing in CarrierWave plugin.
4
+ * Support tags in upload_large.
5
+ * Support url_suffix and use_root_path for private_cdn URL building.
6
+ * Allow using sign_url with type authenticated.
7
+ * Don't sign version component by default.
8
+ * Support for new domain sharding syntax and secure domain sharding. Support for secure_cdn_subdomain flag.
9
+ * Update Cloudinary's jQuery plugin to v1.0.21.
10
+
1
11
  = Version 1.0.78 - 2014-11-04
2
12
  * Add app_root method that handled Rails.root, which is a String in old Rails versions.
3
13
  * Issue #127 - solve cyclical dependency in case cloudinary was included after Rails was initialized.
@@ -171,6 +171,14 @@ class Cloudinary::Api
171
171
  params = Cloudinary::Uploader.build_upload_params(options)
172
172
  call_api(:post, "upload_presets", params.merge(only(options, :name, :unsigned, :disallow_public_id)), options)
173
173
  end
174
+
175
+ def self.root_folders(options={})
176
+ call_api(:get, "folders", {}, options)
177
+ end
178
+
179
+ def self.subfolders(of_folder_path, options={})
180
+ call_api(:get, "folders/#{of_folder_path}", {}, options)
181
+ end
174
182
 
175
183
  protected
176
184
 
@@ -1,6 +1,6 @@
1
1
  # Copyright Cloudinary
2
2
  # Support for store in CarrierWave files that were preloaded to cloudinary (e.g., by javascript)
3
- # Field value must be in the format: "image/upload/v<version>/#<public_id>.<format>#<signature>"
3
+ # Field value must be in the format: "image/upload/v<version>/<public_id>.<format>#<signature>"
4
4
  # Where signature is the cloduinary API signature on the public_id and version.
5
5
  module Cloudinary::CarrierWave
6
6
  PRELOADED_CLOUDINARY_PATH = Cloudinary::PreloadedFile::PRELOADED_CLOUDINARY_PATH
@@ -90,4 +90,4 @@ module Cloudinary::CarrierWave
90
90
  return PreloadedCloudinaryFile.new(file) if file.is_a?(String) && file.match(PRELOADED_CLOUDINARY_PATH)
91
91
  nil
92
92
  end
93
- end
93
+ end
@@ -3,48 +3,48 @@ module Cloudinary::CarrierWave
3
3
  def make_private
4
4
  self.storage_type = :private
5
5
  end
6
-
6
+
7
7
  def process_all_versions(*args)
8
8
  @all_versions ||= Class.new(self)
9
9
  @all_versions.process *args
10
10
  end
11
-
11
+
12
12
  def eager
13
13
  process :eager => true
14
14
  end
15
-
15
+
16
16
  def convert(format)
17
17
  process :convert => format
18
18
  end
19
-
19
+
20
20
  def resize_to_limit(width, height)
21
21
  process :resize_to_limit => [width, height]
22
22
  end
23
-
23
+
24
24
  def resize_to_fit(width, height)
25
25
  process :resize_to_fit => [width, height]
26
26
  end
27
-
27
+
28
28
  def resize_to_fill(width, height, gravity="Center")
29
29
  process :resize_to_fill => [width, height, gravity]
30
30
  end
31
-
31
+
32
32
  def resize_and_pad(width, height, background=:transparent, gravity="Center")
33
33
  process :resize_and_pad => [width, height, background, gravity]
34
- end
35
-
34
+ end
35
+
36
36
  def scale(width, height)
37
37
  process :scale => [width, height]
38
- end
39
-
38
+ end
39
+
40
40
  def crop(width, height, gravity="Center")
41
41
  process :crop => [width, height, gravity]
42
42
  end
43
-
43
+
44
44
  def cloudinary_transformation(options)
45
45
  process :cloudinary_transformation => options
46
46
  end
47
-
47
+
48
48
  def tags(*tags)
49
49
  process :tags=>tags
50
50
  end
@@ -54,35 +54,43 @@ module Cloudinary::CarrierWave
54
54
  raise CloudinaryException, "conflicting transformation on #{attr} #{value}!=#{hash[attr]}" if hash[attr] && hash[attr] != value
55
55
  hash[attr] = value
56
56
  end
57
-
57
+
58
58
  def transformation
59
59
  return @transformation if @transformation
60
60
  @transformation = {}
61
- self.all_processors.each do
62
- |name, args|
61
+ self.all_processors.each do |name, args, condition|
62
+
63
+ if(condition)
64
+ if condition.respond_to?(:call)
65
+ next unless condition.call(self, :args => args)
66
+ else
67
+ next unless self.send(condition)
68
+ end
69
+ end
70
+
63
71
  case name
64
72
  when :convert # Do nothing. This is handled by format
65
- when :resize_to_limit
66
- set_or_yell(@transformation, :width, args[0])
73
+ when :resize_to_limit
74
+ set_or_yell(@transformation, :width, args[0])
67
75
  set_or_yell(@transformation, :height, args[1])
68
76
  set_or_yell(@transformation, :crop, :limit)
69
- when :resize_to_fit
70
- set_or_yell(@transformation, :width, args[0])
77
+ when :resize_to_fit
78
+ set_or_yell(@transformation, :width, args[0])
71
79
  set_or_yell(@transformation, :height, args[1])
72
80
  set_or_yell(@transformation, :crop, :fit)
73
81
  when :resize_to_fill
74
- set_or_yell(@transformation, :width, args[0])
82
+ set_or_yell(@transformation, :width, args[0])
75
83
  set_or_yell(@transformation, :height, args[1])
76
84
  set_or_yell(@transformation, :gravity, args[2].to_s.downcase)
77
85
  set_or_yell(@transformation, :crop, :fill)
78
86
  when :resize_and_pad
79
- set_or_yell(@transformation, :width, args[0])
87
+ set_or_yell(@transformation, :width, args[0])
80
88
  set_or_yell(@transformation, :height, args[1])
81
89
  set_or_yell(@transformation, :background, args[2].to_s.downcase)
82
90
  set_or_yell(@transformation, :gravity, args[3].to_s.downcase)
83
91
  set_or_yell(@transformation, :crop, :pad)
84
- when :scale
85
- set_or_yell(@transformation, :width, args[0])
92
+ when :scale
93
+ set_or_yell(@transformation, :width, args[0])
86
94
  set_or_yell(@transformation, :height, args[1])
87
95
  set_or_yell(@transformation, :crop, :scale)
88
96
  when :crop
@@ -92,28 +100,28 @@ module Cloudinary::CarrierWave
92
100
  set_or_yell(@transformation, :crop, :crop)
93
101
  when :cloudinary_transformation
94
102
  args.each do
95
- |attr, value|
103
+ |attr, value|
96
104
  set_or_yell(@transformation, attr, value)
97
105
  end
98
106
  else
99
107
  if args.blank?
100
108
  send(name).each do
101
- |attr, value|
109
+ |attr, value|
102
110
  set_or_yell(@transformation, attr, value)
103
111
  end
104
112
  end
105
113
  end
106
114
  end
107
- @transformation
115
+ @transformation
108
116
  end
109
117
 
110
118
  def all_versions_processors
111
119
  all_versions = self.class.instance_variable_get('@all_versions')
112
-
120
+
113
121
  all_versions ? all_versions.processors : []
114
122
  end
115
123
 
116
- def all_processors
124
+ def all_processors
117
125
  (self.is_main_uploader? ? [] : all_versions_processors) + self.class.processors
118
126
  end
119
127
 
@@ -126,22 +134,22 @@ module Cloudinary::CarrierWave
126
134
  raise CloudinaryException, "tags cannot be used in versions." if @tags.present? && self.version_name.present?
127
135
  @tags
128
136
  end
129
-
137
+
130
138
  def format
131
139
  format_processor = self.all_processors.find{|processor| processor[0] == :convert}
132
- if format_processor
140
+ if format_processor
133
141
  # Explicit format is given
134
- format = Array(format_processor[1]).first
142
+ format = Array(format_processor[1]).first
135
143
  elsif self.transformation.include?(:format)
136
144
  format = self.transformation[:format]
137
- elsif self.version_name.present?
145
+ elsif self.version_name.present?
138
146
  # No local format. The reset should be handled by main uploader
139
147
  uploader = self.model.send(self.mounted_as)
140
148
  format = uploader.format
141
149
  else
142
150
  # Try to auto-detect format
143
151
  format = Cloudinary::PreloadedFile.split_format(original_filename || "").last
144
- format ||= "png" # TODO Default format?
152
+ format ||= "png" # TODO Default format?
145
153
  end
146
154
  format = format.to_s.downcase
147
155
  Cloudinary::FORMAT_ALIASES[format] || format
@@ -118,6 +118,7 @@ class Cloudinary::Uploader
118
118
  :backup=>options[:backup],
119
119
  :final=>options[:final],
120
120
  :part_number=>options[:part_number],
121
+ :tags=>options[:tags] && Cloudinary::Utils.build_array(options[:tags]).join(","),
121
122
  :upload_id=>options[:upload_id]
122
123
  }
123
124
  if file.is_a?(Pathname) || !file.respond_to?(:read)
@@ -124,9 +124,17 @@ class Cloudinary::Utils
124
124
  shorten = config_option_consume(options, :shorten)
125
125
  force_remote = options.delete(:force_remote)
126
126
  cdn_subdomain = config_option_consume(options, :cdn_subdomain)
127
+ secure_cdn_subdomain = config_option_consume(options, :secure_cdn_subdomain)
127
128
  sign_url = config_option_consume(options, :sign_url)
128
129
  secret = config_option_consume(options, :api_secret)
129
-
130
+ sign_version = config_option_consume(options, :sign_version) # Deprecated behavior
131
+ url_suffix = options.delete(:url_suffix)
132
+ use_root_path = config_option_consume(options, :use_root_path)
133
+ if !private_cdn
134
+ raise(CloudinaryException, "URL Suffix only supported in private CDN") unless url_suffix.blank?
135
+ raise(CloudinaryException, "Root path only supported in private CDN") if use_root_path
136
+ end
137
+
130
138
  original_source = source
131
139
  return original_source if source.blank?
132
140
  if defined?(CarrierWave::Uploader::Base) && source.is_a?(CarrierWave::Uploader::Base)
@@ -152,47 +160,107 @@ class Cloudinary::Utils
152
160
  end
153
161
  end
154
162
 
155
- type ||= :upload
163
+ resource_type, type = finalize_resource_type(resource_type, type, url_suffix, use_root_path, shorten)
164
+ source, source_to_sign = finalize_source(source, format, url_suffix)
165
+
166
+ version ||= 1 if source_to_sign.include?("/") and !source_to_sign.match(/^v[0-9]+/) and !source_to_sign.match(/^https?:\//)
167
+ version &&= "v#{version}"
168
+
169
+ transformation = transformation.gsub(%r(([^:])//), '\1/')
170
+ if sign_url
171
+ to_sign = [transformation, sign_version && version, source_to_sign].reject(&:blank?).join("/")
172
+ signature = 's--' + Base64.urlsafe_encode64(Digest::SHA1.digest(to_sign + secret))[0,8] + '--'
173
+ end
174
+
175
+ prefix = unsigned_download_url_prefix(source, cloud_name, private_cdn, cdn_subdomain, secure_cdn_subdomain, cname, secure, secure_distribution)
176
+ source = [prefix, resource_type, type, signature, transformation, version, source].reject(&:blank?).join("/")
177
+ end
156
178
 
179
+ def self.finalize_source(source, format, url_suffix)
180
+ source = source.gsub(%r(([^:])//), '\1/')
157
181
  if source.match(%r(^https?:/)i)
158
182
  source = smart_escape(source)
183
+ source_to_sign = source
159
184
  else
160
185
  source = smart_escape(URI.decode(source))
161
- source = "#{source}.#{format}" if !format.blank?
186
+ source_to_sign = source
187
+ unless url_suffix.blank?
188
+ raise(CloudinaryException, "url_suffix should not include . or /") if url_suffix.match(%r([\./]))
189
+ source = "#{source}/#{url_suffix}"
190
+ end
191
+ if !format.blank?
192
+ source = "#{source}.#{format}"
193
+ source_to_sign = "#{source_to_sign}.#{format}"
194
+ end
162
195
  end
196
+ [source, source_to_sign]
197
+ end
163
198
 
164
- if cloud_name.start_with?("/") # For development
165
- prefix = "/res" + cloud_name
166
- else
167
- shared_domain = !private_cdn
168
- if secure
169
- if secure_distribution.nil? || secure_distribution == Cloudinary::OLD_AKAMAI_SHARED_CDN
170
- secure_distribution = private_cdn ? "#{cloud_name}-res.cloudinary.com" : Cloudinary::SHARED_CDN
171
- end
172
- shared_domain ||= secure_distribution == Cloudinary::SHARED_CDN
173
- prefix = "https://#{secure_distribution}"
199
+ def self.finalize_resource_type(resource_type, type, url_suffix, use_root_path, shorten)
200
+ type ||= :upload
201
+ if !url_suffix.blank?
202
+ if resource_type.to_s == "image" && type.to_s == "upload"
203
+ resource_type = "images"
204
+ type = nil
205
+ elsif resource_type.to_s == "raw" && type.to_s == "upload"
206
+ resource_type = "files"
207
+ type = nil
174
208
  else
175
- subdomain = cdn_subdomain ? "a#{(Zlib::crc32(source) % 5) + 1}." : ""
176
- host = cname.blank? ? "#{private_cdn ? "#{cloud_name}-" : ""}res.cloudinary.com" : cname
177
- prefix = "http://#{subdomain}#{host}"
209
+ raise(CloudinaryException, "URL Suffix only supported for image/upload and raw/upload")
210
+ end
211
+ end
212
+ if use_root_path
213
+ if (resource_type.to_s == "image" && type.to_s == "upload") || (resource_type.to_s == "images" && type.blank?)
214
+ resource_type = nil
215
+ type = nil
216
+ else
217
+ raise(CloudinaryException, "Root path only supported for image/upload")
178
218
  end
179
- prefix += "/#{cloud_name}" if shared_domain
180
219
  end
181
-
182
220
  if shorten && resource_type.to_s == "image" && type.to_s == "upload"
183
221
  resource_type = "iu"
184
222
  type = nil
185
223
  end
186
- version ||= 1 if source.include?("/") and !source.match(/^v[0-9]+/) and !source.match(/^https?:\//)
187
-
188
- rest = [transformation, version ? "v#{version}" : nil, source].reject(&:blank?).join("/").gsub(%r(([^:])//), '\1/')
189
- if sign_url
190
- rest = 's--' + Base64.urlsafe_encode64(Digest::SHA1.digest(rest + secret))[0,8] + '--/' + rest
224
+ [resource_type, type]
225
+ end
226
+
227
+ # cdn_subdomain and secure_cdn_subdomain
228
+ # 1) Customers in shared distribution (e.g. res.cloudinary.com)
229
+ # if cdn_domain is true uses res-[1-5].cloudinary.com for both http and https. Setting secure_cdn_subdomain to false disables this for https.
230
+ # 2) Customers with private cdn
231
+ # if cdn_domain is true uses cloudname-res-[1-5].cloudinary.com for http
232
+ # if secure_cdn_domain is true uses cloudname-res-[1-5].cloudinary.com for https (please contact support if you require this)
233
+ # 3) Customers with cname
234
+ # if cdn_domain is true uses a[1-5].cname for http. For https, uses the same naming scheme as 1 for shared distribution and as 2 for private distribution.
235
+ def self.unsigned_download_url_prefix(source, cloud_name, private_cdn, cdn_subdomain, secure_cdn_subdomain, cname, secure, secure_distribution)
236
+ return "/res#{cloud_name}" if cloud_name.start_with?("/") # For development
237
+
238
+ shared_domain = !private_cdn
239
+
240
+ if secure
241
+ if secure_distribution.nil? || secure_distribution == Cloudinary::OLD_AKAMAI_SHARED_CDN
242
+ secure_distribution = private_cdn ? "#{cloud_name}-res.cloudinary.com" : Cloudinary::SHARED_CDN
243
+ end
244
+ shared_domain ||= secure_distribution == Cloudinary::SHARED_CDN
245
+ secure_cdn_subdomain = cdn_subdomain if secure_cdn_subdomain.nil? && shared_domain
246
+
247
+ if secure_cdn_subdomain
248
+ secure_distribution = secure_distribution.gsub('res.cloudinary.com', "res-#{(Zlib::crc32(source) % 5) + 1}.cloudinary.com")
249
+ end
250
+
251
+ prefix = "https://#{secure_distribution}"
252
+ elsif cname
253
+ subdomain = cdn_subdomain ? "a#{(Zlib::crc32(source) % 5) + 1}." : ""
254
+ prefix = "http://#{subdomain}#{cname}"
255
+ else
256
+ host = [private_cdn ? "#{cloud_name}-" : "", "res", cdn_subdomain ? "-#{(Zlib::crc32(source) % 5) + 1}" : "", ".cloudinary.com"].join
257
+ prefix = "http://#{host}"
191
258
  end
192
-
193
- source = prefix + "/" + [resource_type, type, rest].reject(&:blank?).join("/").gsub(%r(([^:])//), '\1/')
259
+ prefix += "/#{cloud_name}" if shared_domain
260
+
261
+ prefix
194
262
  end
195
-
263
+
196
264
  def self.cloudinary_api_url(action = 'upload', options = {})
197
265
  cloudinary = options[:upload_prefix] || Cloudinary.config.upload_prefix || "https://api.cloudinary.com"
198
266
  cloud_name = options[:cloud_name] || Cloudinary.config.cloud_name || raise(CloudinaryException, "Must supply cloud_name")
@@ -239,7 +307,7 @@ class Cloudinary::Utils
239
307
  end
240
308
 
241
309
  def self.cloudinary_url(public_id, options = {})
242
- if options[:type].to_s == 'authenticated'
310
+ if options[:type].to_s == 'authenticated' && !options[:sign_url]
243
311
  result = signed_download_url(public_id, options)
244
312
  else
245
313
  result = unsigned_download_url(public_id, options)
@@ -1,4 +1,4 @@
1
1
  # Copyright Cloudinary
2
2
  module Cloudinary
3
- VERSION = "1.0.78"
3
+ VERSION = "1.0.79"
4
4
  end
@@ -21,53 +21,53 @@ describe Cloudinary::Api do
21
21
  end
22
22
 
23
23
  it "should allow listing resource_types" do
24
- @api.resource_types()["resource_types"].should include("image")
24
+ expect(@api.resource_types()["resource_types"]).to include("image")
25
25
  end
26
26
 
27
27
  it "should allow listing resources" do
28
28
  resource = @api.resources()["resources"].find{|resource| resource["public_id"] == "api_test"}
29
- resource.should_not be_blank
30
- resource["type"].should == "upload"
29
+ expect(resource).not_to be_blank
30
+ expect(resource["type"]).to eq("upload")
31
31
  end
32
32
 
33
33
  it "should allow listing resources with cursor" do
34
34
  result = @api.resources(:max_results=>1)
35
- result["resources"].should_not be_blank
36
- result["resources"].length.should == 1
37
- result["next_cursor"].should_not be_blank
35
+ expect(result["resources"]).not_to be_blank
36
+ expect(result["resources"].length).to eq(1)
37
+ expect(result["next_cursor"]).not_to be_blank
38
38
  result2 = @api.resources(:max_results=>1, :next_cursor=>result["next_cursor"])
39
- result2["resources"].should_not be_blank
40
- result2["resources"].length.should == 1
41
- result2["resources"][0]["public_id"].should_not == result["resources"][0]["public_id"]
39
+ expect(result2["resources"]).not_to be_blank
40
+ expect(result2["resources"].length).to eq(1)
41
+ expect(result2["resources"][0]["public_id"]).not_to eq(result["resources"][0]["public_id"] )
42
42
  end
43
43
 
44
44
 
45
45
  it "should allow listing resources by type" do
46
46
  resource = @api.resources(:type=>"upload", :tags=>true)["resources"].find{|resource| resource["public_id"] == "api_test"}
47
- resource.should_not be_blank
48
- resource["tags"].should == ["api_test_tag", @timestamp_tag]
47
+ expect(resource).not_to be_blank
48
+ expect(resource["tags"]).to eq(["api_test_tag", @timestamp_tag])
49
49
  end
50
50
 
51
51
  it "should allow listing resources by prefix" do
52
52
  resources = @api.resources(:type=>"upload", :prefix=>"api_test", :tags => true, :context => true)["resources"]
53
- resources.map{|resource| resource["public_id"]}.should include("api_test", "api_test2")
54
- resources.map{|resource| resource["tags"]}.should include(["api_test_tag", @timestamp_tag])
55
- resources.map{|resource| resource["context"]}.should include({"custom" => {"key" => "value"}})
53
+ expect(resources.map{|resource| resource["public_id"]}).to include("api_test", "api_test2")
54
+ expect(resources.map{|resource| resource["tags"]}).to include(["api_test_tag", @timestamp_tag])
55
+ expect(resources.map{|resource| resource["context"]}).to include({"custom" => {"key" => "value"}})
56
56
  end
57
57
 
58
58
  it "should allow listing resources by tag" do
59
59
  resources = @api.resources_by_tag("api_test_tag", :tags => true, :context => true)["resources"]
60
- resources.find{|resource| resource["public_id"] == "api_test"}.should_not be_blank
61
- resources.map{|resource| resource["tags"]}.should include(["api_test_tag", @timestamp_tag])
62
- resources.map{|resource| resource["context"]}.should include({"custom" => {"key" => "value"}})
60
+ expect(resources.find{|resource| resource["public_id"] == "api_test"}).not_to be_blank
61
+ expect(resources.map{|resource| resource["tags"]}).to include(["api_test_tag", @timestamp_tag])
62
+ expect(resources.map{|resource| resource["context"]}).to include({"custom" => {"key" => "value"}})
63
63
  end
64
64
 
65
65
  it "should allow listing resources by public ids" do
66
66
  resources = @api.resources_by_ids(["api_test", "api_test2"], :tags => true, :context => true)["resources"]
67
- resources.length.should == 2
68
- resources.find{|resource| resource["public_id"] == "api_test"}.should_not be_blank
69
- resources.map{|resource| resource["tags"]}.should include(["api_test_tag", @timestamp_tag])
70
- resources.map{|resource| resource["context"]}.should include({"custom" => {"key" => "value"}})
67
+ expect(resources.length).to eq(2)
68
+ expect(resources.find{|resource| resource["public_id"] == "api_test"}).not_to be_blank
69
+ expect(resources.map{|resource| resource["tags"]}).to include(["api_test_tag", @timestamp_tag])
70
+ expect(resources.map{|resource| resource["context"]}).to include({"custom" => {"key" => "value"}})
71
71
  end
72
72
 
73
73
  it "should allow listing resources by start date", :start_at => true do
@@ -76,7 +76,7 @@ describe Cloudinary::Api do
76
76
  sleep(2)
77
77
  response = Cloudinary::Uploader.upload("spec/logo.png")
78
78
  resources = @api.resources(:type=>"upload", :start_at=>start_at, :direction => "asc")["resources"]
79
- resources.map{|resource| resource["public_id"]}.should == [response["public_id"]]
79
+ expect(resources.map{|resource| resource["public_id"]}) == [response["public_id"]]
80
80
  end
81
81
 
82
82
  it "should allow listing resources in both directions" do
@@ -84,132 +84,132 @@ describe Cloudinary::Api do
84
84
  desc_resources = @api.resources_by_tag(@timestamp_tag, :type=>"upload", :direction => "desc")["resources"]
85
85
  # NOTE: this assumes the full list fits in a page which is the case unless resources with 'api_test' prefix were
86
86
  # uploaded to the account against which this test runs
87
- asc_resources.reverse.should == desc_resources
87
+ expect(asc_resources.reverse).to eq(desc_resources)
88
88
  asc_resources_alt = @api.resources_by_tag(@timestamp_tag, :type=>"upload", :direction => 1)["resources"]
89
89
  desc_resources_alt = @api.resources_by_tag(@timestamp_tag, :type=>"upload", :direction => -1)["resources"]
90
- asc_resources_alt.reverse.should == desc_resources_alt
91
- asc_resources.should == asc_resources_alt
92
- lambda{@api.resources_by_tag(@timestamp_tag, :type=>"upload", :direction => "anythingelse")["resources"]}.should raise_error(Cloudinary::Api::BadRequest)
90
+ expect(asc_resources_alt.reverse).to eq(desc_resources_alt)
91
+ expect(asc_resources).to eq(asc_resources_alt)
92
+ expect{@api.resources_by_tag(@timestamp_tag, :type=>"upload", :direction => "anythingelse")["resources"]}.to raise_error(Cloudinary::Api::BadRequest)
93
93
  end
94
94
 
95
95
  it "should allow get resource metadata" do
96
96
  resource = @api.resource("api_test")
97
- resource.should_not be_blank
98
- resource["public_id"].should == "api_test"
99
- resource["bytes"].should == 3381
100
- resource["derived"].length.should == 1
97
+ expect(resource).not_to be_blank
98
+ expect(resource["public_id"]).to eq("api_test")
99
+ expect(resource["bytes"]).to eq(3381)
100
+ expect(resource["derived"].length).to eq(1)
101
101
  end
102
102
 
103
103
  it "should allow deleting derived resource" do
104
104
  Cloudinary::Uploader.upload("spec/logo.png", :public_id=>"api_test3", :eager=>[:width=>101,:crop=>:scale])
105
105
  resource = @api.resource("api_test3")
106
- resource.should_not be_blank
107
- resource["derived"].length.should == 1
106
+ expect(resource).not_to be_blank
107
+ expect(resource["derived"].length).to eq(1)
108
108
  derived_resource_id = resource["derived"][0]["id"]
109
109
  @api.delete_derived_resources(derived_resource_id)
110
110
  resource = @api.resource("api_test3")
111
- resource.should_not be_blank
112
- resource["derived"].length.should == 0
111
+ expect(resource).not_to be_blank
112
+ expect(resource["derived"].length).to eq(0)
113
113
  end
114
114
 
115
115
  it "should allow deleting resources" do
116
116
  Cloudinary::Uploader.upload("spec/logo.png", :public_id=>"api_test3")
117
117
  resource = @api.resource("api_test3")
118
- resource.should_not be_blank
118
+ expect(resource).not_to be_blank
119
119
  @api.delete_resources(["apit_test", "api_test2", "api_test3"])
120
- lambda{@api.resource("api_test3")}.should raise_error(Cloudinary::Api::NotFound)
120
+ expect{@api.resource("api_test3")}.to raise_error(Cloudinary::Api::NotFound)
121
121
  end
122
122
 
123
123
  it "should allow deleting resources by prefix" do
124
124
  Cloudinary::Uploader.upload("spec/logo.png", :public_id=>"api_test_by_prefix")
125
125
  resource = @api.resource("api_test_by_prefix")
126
- resource.should_not be_blank
126
+ expect(resource).not_to be_blank
127
127
  @api.delete_resources_by_prefix("api_test_by")
128
- lambda{@api.resource("api_test_by_prefix")}.should raise_error(Cloudinary::Api::NotFound)
128
+ expect{@api.resource("api_test_by_prefix")}.to raise_error(Cloudinary::Api::NotFound)
129
129
  end
130
130
 
131
131
  it "should allow deleting resources by tags" do
132
132
  Cloudinary::Uploader.upload("spec/logo.png", :public_id=>"api_test4", :tags=>["api_test_tag_for_delete"])
133
133
  resource = @api.resource("api_test4")
134
- resource.should_not be_blank
134
+ expect(resource).not_to be_blank
135
135
  @api.delete_resources_by_tag("api_test_tag_for_delete")
136
- lambda{@api.resource("api_test4")}.should raise_error(Cloudinary::Api::NotFound)
136
+ expect{@api.resource("api_test4")}.to raise_error(Cloudinary::Api::NotFound)
137
137
  end
138
138
 
139
139
  it "should allow listing tags" do
140
140
  tags = @api.tags()["tags"]
141
- tags.should include('api_test_tag')
141
+ expect(tags).to include('api_test_tag')
142
142
  end
143
143
 
144
144
  it "should allow listing tag by prefix" do
145
145
  tags = @api.tags(:prefix=>"api_test")["tags"]
146
- tags.should include('api_test_tag')
146
+ expect(tags).to include('api_test_tag')
147
147
  tags = @api.tags(:prefix=>"api_test_no_such_tag")["tags"]
148
- tags.should be_blank
148
+ expect(tags).to be_blank
149
149
  end
150
150
 
151
151
  it "should allow listing transformations" do
152
152
  transformation = @api.transformations()["transformations"].find{|transformation| transformation["name"] == "c_scale,w_100"}
153
- transformation.should_not be_blank
154
- transformation["used"].should == true
153
+ expect(transformation).not_to be_blank
154
+ expect(transformation["used"]).to eq(true)
155
155
  end
156
156
 
157
157
  it "should allow getting transformation metadata" do
158
158
  transformation = @api.transformation("c_scale,w_100")
159
- transformation.should_not be_blank
160
- transformation["info"].should == ["crop"=>"scale", "width"=>100]
159
+ expect(transformation).not_to be_blank
160
+ expect(transformation["info"]).to eq(["crop"=>"scale", "width"=>100] )
161
161
  transformation = @api.transformation("crop"=>"scale", "width"=>100)
162
- transformation.should_not be_blank
163
- transformation["info"].should == ["crop"=>"scale", "width"=>100]
162
+ expect(transformation).not_to be_blank
163
+ expect(transformation["info"]).to eq(["crop"=>"scale", "width"=>100] )
164
164
  end
165
165
 
166
166
  it "should allow updating transformation allowed_for_strict" do
167
167
  @api.update_transformation("c_scale,w_100", :allowed_for_strict=>true)
168
168
  transformation = @api.transformation("c_scale,w_100")
169
- transformation.should_not be_blank
170
- transformation["allowed_for_strict"].should == true
169
+ expect(transformation).not_to be_blank
170
+ expect(transformation["allowed_for_strict"]).to eq(true)
171
171
  @api.update_transformation("c_scale,w_100", :allowed_for_strict=>false)
172
172
  transformation = @api.transformation("c_scale,w_100")
173
- transformation.should_not be_blank
174
- transformation["allowed_for_strict"].should == false
173
+ expect(transformation).not_to be_blank
174
+ expect(transformation["allowed_for_strict"]).to eq(false)
175
175
  end
176
176
 
177
177
  it "should allow creating named transformation" do
178
178
  @api.create_transformation("api_test_transformation", "crop"=>"scale", "width"=>102)
179
179
  transformation = @api.transformation("api_test_transformation")
180
- transformation.should_not be_blank
181
- transformation["allowed_for_strict"].should == true
182
- transformation["info"].should == ["crop"=>"scale", "width"=>102]
183
- transformation["used"].should == false
180
+ expect(transformation).not_to be_blank
181
+ expect(transformation["allowed_for_strict"]).to eq(true)
182
+ expect(transformation["info"]).to eq(["crop"=>"scale", "width"=>102])
183
+ expect(transformation["used"]).to eq(false)
184
184
  end
185
185
 
186
186
  it "should allow deleting named transformation" do
187
187
  @api.create_transformation("api_test_transformation2", "crop"=>"scale", "width"=>103)
188
188
  @api.transformation("api_test_transformation2")
189
189
  @api.delete_transformation("api_test_transformation2")
190
- lambda{@api.transformation("api_test_transformation2")}.should raise_error(Cloudinary::Api::NotFound)
190
+ expect{@api.transformation("api_test_transformation2")}.to raise_error(Cloudinary::Api::NotFound)
191
191
  end
192
192
 
193
193
  it "should allow unsafe update of named transformation" do
194
194
  @api.create_transformation("api_test_transformation3", "crop"=>"scale", "width"=>102)
195
195
  @api.update_transformation("api_test_transformation3", :unsafe_update=>{"crop"=>"scale", "width"=>103})
196
196
  transformation = @api.transformation("api_test_transformation3")
197
- transformation.should_not be_blank
198
- transformation["info"].should == ["crop"=>"scale", "width"=>103]
199
- transformation["used"].should == false
197
+ expect(transformation).not_to be_blank
198
+ expect(transformation["info"]).to eq(["crop"=>"scale", "width"=>103])
199
+ expect(transformation["used"]).to eq(false)
200
200
  end
201
201
 
202
202
  it "should allow deleting implicit transformation" do
203
203
  @api.transformation("c_scale,w_100")
204
204
  @api.delete_transformation("c_scale,w_100")
205
- lambda{@api.transformation("c_scale,w_100")}.should raise_error(Cloudinary::Api::NotFound)
205
+ expect{@api.transformation("c_scale,w_100")}.to raise_error(Cloudinary::Api::NotFound)
206
206
  end
207
207
 
208
208
  it "should allow creating and listing upload_presets", :upload_preset => true do
209
209
  @api.create_upload_preset(:name => "api_test_upload_preset", :folder => "folder")
210
210
  @api.create_upload_preset(:name => "api_test_upload_preset2", :folder => "folder2")
211
211
  @api.create_upload_preset(:name => "api_test_upload_preset3", :folder => "folder3")
212
- @api.upload_presets["presets"].first(3).map{|p| p["name"]}.should == ["api_test_upload_preset3", "api_test_upload_preset2", "api_test_upload_preset"]
212
+ expect(@api.upload_presets["presets"].first(3).map{|p| p["name"]}).to eq(["api_test_upload_preset3", "api_test_upload_preset2", "api_test_upload_preset"])
213
213
  @api.delete_upload_preset("api_test_upload_preset")
214
214
  @api.delete_upload_preset("api_test_upload_preset2")
215
215
  @api.delete_upload_preset("api_test_upload_preset3")
@@ -219,12 +219,12 @@ describe Cloudinary::Api do
219
219
  result = @api.create_upload_preset(:unsigned => true, :folder => "folder", :width => 100, :crop => :scale, :tags => ["a","b","c"], :context => {:a => "b", :c => "d"})
220
220
  name = result["name"]
221
221
  preset = @api.upload_preset(name)
222
- preset["name"].should == name
223
- preset["unsigned"].should == true
224
- preset["settings"]["folder"].should == "folder"
225
- preset["settings"]["transformation"].should == [{"width" => 100, "crop" => "scale"}]
226
- preset["settings"]["context"].should == {"a" => "b", "c" => "d"}
227
- preset["settings"]["tags"].should == ["a","b","c"]
222
+ expect(preset["name"]).to eq(name)
223
+ expect(preset["unsigned"]).to eq(true)
224
+ expect(preset["settings"]["folder"]).to eq("folder")
225
+ expect(preset["settings"]["transformation"]).to eq([{"width" => 100, "crop" => "scale"}])
226
+ expect(preset["settings"]["context"]).to eq({"a" => "b", "c" => "d"})
227
+ expect(preset["settings"]["tags"]).to eq(["a","b","c"])
228
228
  @api.delete_upload_preset(name)
229
229
  end
230
230
 
@@ -232,7 +232,7 @@ describe Cloudinary::Api do
232
232
  @api.create_upload_preset(:name => "api_test_upload_preset4", :folder => "folder")
233
233
  preset = @api.upload_preset("api_test_upload_preset4")
234
234
  @api.delete_upload_preset("api_test_upload_preset4")
235
- lambda{preset = @api.upload_preset("api_test_upload_preset4")}.should raise_error
235
+ expect{preset = @api.upload_preset("api_test_upload_preset4")}.to raise_error
236
236
  end
237
237
 
238
238
  it "should allow updating upload_presets", :upload_preset => true do
@@ -240,9 +240,9 @@ describe Cloudinary::Api do
240
240
  preset = @api.upload_preset(name)
241
241
  @api.update_upload_preset(name, preset["settings"].merge(:colors => true, :unsigned => true, :disallow_public_id => true))
242
242
  preset = @api.upload_preset(name)
243
- preset["name"].should == name
244
- preset["unsigned"].should == true
245
- preset["settings"].should == {"folder" => "folder", "colors" => true, "disallow_public_id" => true}
243
+ expect(preset["name"]).to eq(name)
244
+ expect(preset["unsigned"]).to eq(true)
245
+ expect(preset["settings"]).to eq({"folder" => "folder", "colors" => true, "disallow_public_id" => true})
246
246
  @api.delete_upload_preset(name)
247
247
  end
248
248
 
@@ -250,41 +250,41 @@ describe Cloudinary::Api do
250
250
  it "should allow deleting all resources", :delete_all=>true do
251
251
  Cloudinary::Uploader.upload("spec/logo.png", :public_id=>"api_test5", :eager=>[:width=>101,:crop=>:scale])
252
252
  resource = @api.resource("api_test5")
253
- resource.should_not be_blank
254
- resource["derived"].length.should == 1
253
+ expect(resource).not_to be_blank
254
+ expect(resource["derived"].length).to eq(1)
255
255
  @api.delete_all_resources(:keep_original => true)
256
256
  resource = @api.resource("api_test5")
257
- resource.should_not be_blank
258
- resource["derived"].length.should == 0
257
+ expect(resource).not_to be_blank
258
+ expect(resource["derived"].length).to eq(0)
259
259
  end
260
260
 
261
261
  it "should support setting manual moderation status" do
262
262
  result = Cloudinary::Uploader.upload("spec/logo.png", {:moderation => :manual})
263
- result["moderation"][0]["status"].should == "pending"
264
- result["moderation"][0]["kind"].should == "manual"
263
+ expect(result["moderation"][0]["status"]).to eq("pending")
264
+ expect(result["moderation"][0]["kind"]).to eq("manual")
265
265
  api_result = Cloudinary::Api.update(result["public_id"], {:moderation_status => :approved})
266
- api_result["moderation"][0]["status"].should == "approved"
267
- api_result["moderation"][0]["kind"].should == "manual"
266
+ expect(api_result["moderation"][0]["status"]).to eq("approved")
267
+ expect(api_result["moderation"][0]["kind"]).to eq("manual")
268
268
  end
269
269
 
270
270
  it "should support requesting raw conversion" do
271
271
  result = Cloudinary::Uploader.upload("spec/docx.docx", :resource_type => :raw)
272
- lambda{Cloudinary::Api.update(result["public_id"], {:resource_type => :raw, :raw_convert => :illegal})}.should raise_error(Cloudinary::Api::BadRequest, /^Illegal value|not a valid/)
272
+ expect{Cloudinary::Api.update(result["public_id"], {:resource_type => :raw, :raw_convert => :illegal})}.to raise_error(Cloudinary::Api::BadRequest, /^Illegal value|not a valid/)
273
273
  end
274
274
 
275
275
  it "should support requesting categorization" do
276
276
  result = Cloudinary::Uploader.upload("spec/logo.png")
277
- lambda{Cloudinary::Api.update(result["public_id"], {:categorization => :illegal})}.should raise_error(Cloudinary::Api::BadRequest, /^Illegal value/)
277
+ expect{Cloudinary::Api.update(result["public_id"], {:categorization => :illegal})}.to raise_error(Cloudinary::Api::BadRequest, /^Illegal value/)
278
278
  end
279
279
 
280
280
  it "should support requesting detection" do
281
281
  result = Cloudinary::Uploader.upload("spec/logo.png")
282
- lambda{Cloudinary::Api.update(result["public_id"], {:detection => :illegal})}.should raise_error(Cloudinary::Api::BadRequest, /^Illegal value/)
282
+ expect{Cloudinary::Api.update(result["public_id"], {:detection => :illegal})}.to raise_error(Cloudinary::Api::BadRequest, /^Illegal value/)
283
283
  end
284
284
 
285
285
  it "should support requesting auto_tagging" do
286
286
  result = Cloudinary::Uploader.upload("spec/logo.png")
287
- lambda{Cloudinary::Api.update(result["public_id"], {:auto_tagging => 0.5})}.should raise_error(Cloudinary::Api::BadRequest, /^Must use/)
287
+ expect{Cloudinary::Api.update(result["public_id"], {:auto_tagging => 0.5})}.to raise_error(Cloudinary::Api::BadRequest, /^Must use/)
288
288
  end
289
289
 
290
290
  it "should support listing by moderation kind and value" do
@@ -294,17 +294,34 @@ describe Cloudinary::Api do
294
294
  Cloudinary::Api.update(result1["public_id"], {:moderation_status => :approved})
295
295
  Cloudinary::Api.update(result2["public_id"], {:moderation_status => :rejected})
296
296
  approved = Cloudinary::Api.resources_by_moderation(:manual, :approved, :max_results => 1000)["resources"].map{|r| r["public_id"]}
297
- approved.should include(result1["public_id"])
298
- approved.should_not include(result2["public_id"])
299
- approved.should_not include(result3["public_id"])
297
+ expect(approved).to include(result1["public_id"])
298
+ expect(approved).not_to include(result2["public_id"])
299
+ expect(approved).not_to include(result3["public_id"])
300
300
  rejected = Cloudinary::Api.resources_by_moderation(:manual, :rejected, :max_results => 1000)["resources"].map{|r| r["public_id"]}
301
- rejected.should include(result2["public_id"])
302
- rejected.should_not include(result1["public_id"])
303
- rejected.should_not include(result3["public_id"])
301
+ expect(rejected).to include(result2["public_id"])
302
+ expect(rejected).not_to include(result1["public_id"])
303
+ expect(rejected).not_to include(result3["public_id"])
304
304
  pending = Cloudinary::Api.resources_by_moderation(:manual, :pending, :max_results => 1000)["resources"].map{|r| r["public_id"]}
305
- pending.should include(result3["public_id"])
306
- pending.should_not include(result1["public_id"])
307
- pending.should_not include(result2["public_id"])
305
+ expect(pending).to include(result3["public_id"])
306
+ expect(pending).not_to include(result1["public_id"])
307
+ expect(pending).not_to include(result2["public_id"])
308
308
  end
309
309
 
310
+ it "should support listing folders" do
311
+ pending("For this test to work, 'Auto-create folders' should be enabled in the Upload Settings, " +
312
+ "and the account should be empty of folders. " +
313
+ "Comment out this line if you really want to test it.")
314
+ Cloudinary::Uploader.upload("spec/logo.png", {:public_id => "test_folder1/item"})
315
+ Cloudinary::Uploader.upload("spec/logo.png", {:public_id => "test_folder2/item"})
316
+ Cloudinary::Uploader.upload("spec/logo.png", {:public_id => "test_folder1/test_subfolder1/item"})
317
+ Cloudinary::Uploader.upload("spec/logo.png", {:public_id => "test_folder1/test_subfolder2/item"})
318
+ result = Cloudinary::Api.root_folders
319
+ expect(result["folders"][0]["name"]).to eq("test_folder1")
320
+ expect(result["folders"][1]["name"]).to eq("test_folder2")
321
+ result = Cloudinary::Api.subfolders("test_folder1")
322
+ expect(result["folders"][0]["path"]).to eq("test_folder1/test_subfolder1")
323
+ expect(result["folders"][1]["path"]).to eq("test_folder1/test_subfolder2")
324
+ expect{Cloudinary::Api.subfolders("test_folder")}.to raise_error(Cloudinary::Api::NotFound)
325
+ Cloudinary::Api.delete_resources_by_prefix("test_folder")
326
+ end
310
327
  end