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 +4 -4
- data/CHANGELOG +10 -0
- data/lib/cloudinary/api.rb +8 -0
- data/lib/cloudinary/carrier_wave/preloaded.rb +2 -2
- data/lib/cloudinary/carrier_wave/process.rb +42 -34
- data/lib/cloudinary/uploader.rb +1 -0
- data/lib/cloudinary/utils.rb +95 -27
- data/lib/cloudinary/version.rb +1 -1
- data/spec/api_spec.rb +111 -94
- data/spec/uploader_spec.rb +33 -33
- data/spec/utils_spec.rb +160 -268
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b29c537f39a98d72f302907e0f50fbb8cafa1a10
|
4
|
+
data.tar.gz: b8a1adc7b8fe8f9bc154f909e44b4ef0a16387fc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
data/lib/cloudinary/api.rb
CHANGED
@@ -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
|
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
|
-
|
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
|
data/lib/cloudinary/uploader.rb
CHANGED
@@ -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)
|
data/lib/cloudinary/utils.rb
CHANGED
@@ -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
|
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
|
-
|
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
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
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
|
-
|
176
|
-
|
177
|
-
|
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
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
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
|
-
|
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)
|
data/lib/cloudinary/version.rb
CHANGED
data/spec/api_spec.rb
CHANGED
@@ -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"].
|
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.
|
30
|
-
resource["type"].
|
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"].
|
36
|
-
result["resources"].length.
|
37
|
-
result["next_cursor"].
|
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"].
|
40
|
-
result2["resources"].length.
|
41
|
-
result2["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.
|
48
|
-
resource["tags"].
|
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"]}.
|
54
|
-
resources.map{|resource| resource["tags"]}.
|
55
|
-
resources.map{|resource| resource["context"]}.
|
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"}.
|
61
|
-
resources.map{|resource| resource["tags"]}.
|
62
|
-
resources.map{|resource| resource["context"]}.
|
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.
|
68
|
-
resources.find{|resource| resource["public_id"] == "api_test"}.
|
69
|
-
resources.map{|resource| resource["tags"]}.
|
70
|
-
resources.map{|resource| resource["context"]}.
|
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"]}
|
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.
|
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.
|
91
|
-
asc_resources.
|
92
|
-
|
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.
|
98
|
-
resource["public_id"].
|
99
|
-
resource["bytes"].
|
100
|
-
resource["derived"].length.
|
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.
|
107
|
-
resource["derived"].length.
|
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.
|
112
|
-
resource["derived"].length.
|
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.
|
118
|
+
expect(resource).not_to be_blank
|
119
119
|
@api.delete_resources(["apit_test", "api_test2", "api_test3"])
|
120
|
-
|
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.
|
126
|
+
expect(resource).not_to be_blank
|
127
127
|
@api.delete_resources_by_prefix("api_test_by")
|
128
|
-
|
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.
|
134
|
+
expect(resource).not_to be_blank
|
135
135
|
@api.delete_resources_by_tag("api_test_tag_for_delete")
|
136
|
-
|
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.
|
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.
|
146
|
+
expect(tags).to include('api_test_tag')
|
147
147
|
tags = @api.tags(:prefix=>"api_test_no_such_tag")["tags"]
|
148
|
-
tags.
|
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.
|
154
|
-
transformation["used"].
|
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.
|
160
|
-
transformation["info"].
|
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.
|
163
|
-
transformation["info"].
|
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.
|
170
|
-
transformation["allowed_for_strict"].
|
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.
|
174
|
-
transformation["allowed_for_strict"].
|
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.
|
181
|
-
transformation["allowed_for_strict"].
|
182
|
-
transformation["info"].
|
183
|
-
transformation["used"].
|
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
|
-
|
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.
|
198
|
-
transformation["info"].
|
199
|
-
transformation["used"].
|
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
|
-
|
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"]}.
|
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"].
|
223
|
-
preset["unsigned"].
|
224
|
-
preset["settings"]["folder"].
|
225
|
-
preset["settings"]["transformation"].
|
226
|
-
preset["settings"]["context"].
|
227
|
-
preset["settings"]["tags"].
|
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
|
-
|
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"].
|
244
|
-
preset["unsigned"].
|
245
|
-
preset["settings"].
|
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.
|
254
|
-
resource["derived"].length.
|
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.
|
258
|
-
resource["derived"].length.
|
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"].
|
264
|
-
result["moderation"][0]["kind"].
|
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"].
|
267
|
-
api_result["moderation"][0]["kind"].
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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.
|
298
|
-
approved.
|
299
|
-
approved.
|
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.
|
302
|
-
rejected.
|
303
|
-
rejected.
|
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.
|
306
|
-
pending.
|
307
|
-
pending.
|
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
|