cloudinary 1.0.78 → 1.0.79

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