cloudinary 1.0.66 → 1.0.67
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +8 -0
- data/lib/cloudinary.rb +3 -1
- data/lib/cloudinary/api.rb +10 -3
- data/lib/cloudinary/uploader.rb +7 -3
- data/lib/cloudinary/utils.rb +21 -3
- data/lib/cloudinary/version.rb +1 -1
- data/spec/api_spec.rb +18 -6
- data/spec/uploader_spec.rb +32 -0
- data/spec/utils_spec.rb +22 -1
- metadata +16 -8
- checksums.yaml +0 -15
data/CHANGELOG
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
= Version 1.0.67 - 2014-01-09
|
2
|
+
* Support specifying face coordinates in upload API.
|
3
|
+
* Support specifying context (currently alt and caption) in upload API and returning context in API.
|
4
|
+
* Support specifying allowed image formats in upload API.
|
5
|
+
* Support listing resources in admin API by multiple public IDs.
|
6
|
+
* Send User-Agent header with client library version in API request.
|
7
|
+
* Support for signed-URLs to override restricted dynamic URLs.
|
8
|
+
|
1
9
|
= Version 1.0.66 - 2013-11-14
|
2
10
|
* Support overwrite flag in upload
|
3
11
|
* Support tags flag in resources_by_tag
|
data/lib/cloudinary.rb
CHANGED
@@ -25,7 +25,9 @@ module Cloudinary
|
|
25
25
|
CF_SHARED_CDN = "d3jpl91pxevbkh.cloudfront.net"
|
26
26
|
AKAMAI_SHARED_CDN = "res.cloudinary.com"
|
27
27
|
OLD_AKAMAI_SHARED_CDN = "cloudinary-a.akamaihd.net"
|
28
|
-
SHARED_CDN = AKAMAI_SHARED_CDN
|
28
|
+
SHARED_CDN = AKAMAI_SHARED_CDN
|
29
|
+
|
30
|
+
USER_AGENT = "cld-ruby-" + VERSION
|
29
31
|
|
30
32
|
FORMAT_ALIASES = {
|
31
33
|
"jpeg" => "jpg",
|
data/lib/cloudinary/api.rb
CHANGED
@@ -36,13 +36,20 @@ class Cloudinary::Api
|
|
36
36
|
type = options[:type]
|
37
37
|
uri = "resources/#{resource_type}"
|
38
38
|
uri += "/#{type}" if !type.blank?
|
39
|
-
call_api(:get, uri, only(options, :next_cursor, :max_results, :prefix, :tags), options)
|
39
|
+
call_api(:get, uri, only(options, :next_cursor, :max_results, :prefix, :tags, :context), options)
|
40
40
|
end
|
41
41
|
|
42
42
|
def self.resources_by_tag(tag, options={})
|
43
43
|
resource_type = options[:resource_type] || "image"
|
44
44
|
uri = "resources/#{resource_type}/tags/#{tag}"
|
45
|
-
call_api(:get, uri, only(options, :next_cursor, :max_results, :tags), options)
|
45
|
+
call_api(:get, uri, only(options, :next_cursor, :max_results, :tags, :context), options)
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.resources_by_ids(public_ids, options={})
|
49
|
+
resource_type = options[:resource_type] || "image"
|
50
|
+
type = options[:type] || "upload"
|
51
|
+
uri = "resources/#{resource_type}/#{type}"
|
52
|
+
call_api(:get, uri, only(options, :tags, :context).merge(public_ids: public_ids), options)
|
46
53
|
end
|
47
54
|
|
48
55
|
def self.resource(public_id, options={})
|
@@ -126,7 +133,7 @@ class Cloudinary::Api
|
|
126
133
|
# Add authentication
|
127
134
|
api_url.sub!(%r(^(https?://)), "\\1#{api_key}:#{api_secret}@")
|
128
135
|
|
129
|
-
RestClient::Request.execute(:method => method, :url => api_url, :payload => params.reject{|k, v| v.nil? || v==""}, :timeout=>60) do
|
136
|
+
RestClient::Request.execute(:method => method, :url => api_url, :payload => params.reject{|k, v| v.nil? || v==""}, :timeout=>60, :headers => {"User-Agent" => Cloudinary::USER_AGENT}) do
|
130
137
|
|response, request, tmpresult|
|
131
138
|
return Response.new(response) if response.code == 200
|
132
139
|
exception_class = case response.code
|
data/lib/cloudinary/uploader.rb
CHANGED
@@ -38,7 +38,10 @@ class Cloudinary::Uploader
|
|
38
38
|
:eager_async=>Cloudinary::Utils.as_safe_bool(options[:eager_async]),
|
39
39
|
:proxy=>options[:proxy],
|
40
40
|
:folder=>options[:folder],
|
41
|
-
:tags=>options[:tags] && Cloudinary::Utils.build_array(options[:tags]).join(",")
|
41
|
+
:tags=>options[:tags] && Cloudinary::Utils.build_array(options[:tags]).join(","),
|
42
|
+
:allowed_formats => Cloudinary::Utils.build_array(options[:allowed_formats]).join(","),
|
43
|
+
:context => Cloudinary::Utils.encode_hash(options[:context]),
|
44
|
+
:face_coordinates => Cloudinary::Utils.encode_double_array(options[:face_coordinates])}
|
42
45
|
params
|
43
46
|
end
|
44
47
|
|
@@ -98,7 +101,8 @@ class Cloudinary::Uploader
|
|
98
101
|
:callback=> options[:callback],
|
99
102
|
:eager=>build_eager(options[:eager]),
|
100
103
|
:headers=>build_custom_headers(options[:headers]),
|
101
|
-
:tags=>options[:tags] && Cloudinary::Utils.build_array(options[:tags]).join(",")
|
104
|
+
:tags=>options[:tags] && Cloudinary::Utils.build_array(options[:tags]).join(","),
|
105
|
+
:face_coordinates => options[:face_coordinates] && Cloudinary::Utils.encode_double_array(options[:face_coordinates])
|
102
106
|
}
|
103
107
|
end
|
104
108
|
end
|
@@ -205,7 +209,7 @@ class Cloudinary::Uploader
|
|
205
209
|
|
206
210
|
api_url = Cloudinary::Utils.cloudinary_api_url(action, options)
|
207
211
|
|
208
|
-
RestClient::Request.execute(:method => :post, :url => api_url, :payload => params.reject{|k, v| v.nil? || v==""}, :timeout=>60) do
|
212
|
+
RestClient::Request.execute(:method => :post, :url => api_url, :payload => params.reject{|k, v| v.nil? || v==""}, :timeout=>60, :headers => {"User-Agent" => Cloudinary::USER_AGENT}) do
|
209
213
|
|response, request, tmpresult|
|
210
214
|
raise CloudinaryException, "Server returned unexpected status code - #{response.code} - #{response.body}" if ![200,400,401,403,404,500].include?(response.code)
|
211
215
|
begin
|
data/lib/cloudinary/utils.rb
CHANGED
@@ -107,6 +107,8 @@ class Cloudinary::Utils
|
|
107
107
|
shorten = config_option_consume(options, :shorten)
|
108
108
|
force_remote = options.delete(:force_remote)
|
109
109
|
cdn_subdomain = config_option_consume(options, :cdn_subdomain)
|
110
|
+
sign_url = config_option_consume(options, :sign_url)
|
111
|
+
secret = config_option_consume(options, :api_secret)
|
110
112
|
|
111
113
|
original_source = source
|
112
114
|
return original_source if source.blank?
|
@@ -165,9 +167,13 @@ class Cloudinary::Utils
|
|
165
167
|
type = nil
|
166
168
|
end
|
167
169
|
version ||= 1 if source.include?("/") and !source.match(/^v[0-9]+/) and !source.match(/^https?:\//)
|
168
|
-
|
169
|
-
|
170
|
-
|
170
|
+
|
171
|
+
rest = [transformation, version ? "v#{version}" : nil, source].reject(&:blank?).join("/").gsub(%r(([^:])//), '\1/')
|
172
|
+
if sign_url
|
173
|
+
rest = 's--' + Base64.urlsafe_encode64(Digest::SHA1.digest(rest + secret))[0,8] + '--/' + rest
|
174
|
+
end
|
175
|
+
|
176
|
+
source = prefix + "/" + [resource_type, type, rest].reject(&:blank?).join("/").gsub(%r(([^:])//), '\1/')
|
171
177
|
end
|
172
178
|
|
173
179
|
def self.cloudinary_api_url(action = 'upload', options = {})
|
@@ -272,6 +278,18 @@ class Cloudinary::Utils
|
|
272
278
|
else [array]
|
273
279
|
end
|
274
280
|
end
|
281
|
+
|
282
|
+
def self.encode_hash(hash)
|
283
|
+
case hash
|
284
|
+
when Hash then hash.map{|k,v| "#{k}=#{v}"}.join("|")
|
285
|
+
when nil then ""
|
286
|
+
else hash
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
def self.encode_double_array(array)
|
291
|
+
build_array(array).map{|a| build_array(a).join(",")}.join("|")
|
292
|
+
end
|
275
293
|
|
276
294
|
IMAGE_FORMATS = %w(bmp png tif tiff jpg jpeg gif pdf ico eps jpc jp2 psd)
|
277
295
|
|
data/lib/cloudinary/version.rb
CHANGED
data/spec/api_spec.rb
CHANGED
@@ -8,8 +8,8 @@ describe Cloudinary::Api do
|
|
8
8
|
@api = Cloudinary::Api
|
9
9
|
Cloudinary::Uploader.destroy("api_test")
|
10
10
|
Cloudinary::Uploader.destroy("api_test2")
|
11
|
-
Cloudinary::Uploader.upload("spec/logo.png", :public_id=>"api_test", :tags=>"api_test_tag", :eager=>[:width=>100,:crop=>:scale])
|
12
|
-
Cloudinary::Uploader.upload("spec/logo.png", :public_id=>"api_test2", :tags=>"api_test_tag", :eager=>[:width=>100,:crop=>:scale])
|
11
|
+
Cloudinary::Uploader.upload("spec/logo.png", :public_id=>"api_test", :tags=>"api_test_tag", :context => "key=value", :eager=>[:width=>100,:crop=>:scale])
|
12
|
+
Cloudinary::Uploader.upload("spec/logo.png", :public_id=>"api_test2", :tags=>"api_test_tag", :context => "key=value", :eager=>[:width=>100,:crop=>:scale])
|
13
13
|
@api.delete_transformation("api_test_transformation") rescue nil
|
14
14
|
@api.delete_transformation("api_test_transformation2") rescue nil
|
15
15
|
@api.delete_transformation("api_test_transformation3") rescue nil
|
@@ -44,13 +44,25 @@ describe Cloudinary::Api do
|
|
44
44
|
end
|
45
45
|
|
46
46
|
it "should allow listing resources by prefix" do
|
47
|
-
|
48
|
-
|
47
|
+
resources = @api.resources(:type=>"upload", :prefix=>"api_test", :tags => true, :context => true)["resources"]
|
48
|
+
resources.map{|resource| resource["public_id"]}.should include("api_test", "api_test2")
|
49
|
+
resources.map{|resource| resource["tags"]}.should include(["api_test_tag"])
|
50
|
+
resources.map{|resource| resource["context"]}.should include({"custom" => {"key" => "value"}})
|
49
51
|
end
|
50
52
|
|
51
53
|
it "should allow listing resources by tag" do
|
52
|
-
|
53
|
-
resource.should_not be_blank
|
54
|
+
resources = @api.resources_by_tag("api_test_tag", :tags => true, :context => true)["resources"]
|
55
|
+
resources.find{|resource| resource["public_id"] == "api_test"}.should_not be_blank
|
56
|
+
resources.map{|resource| resource["tags"]}.should include(["api_test_tag"])
|
57
|
+
resources.map{|resource| resource["context"]}.should include({"custom" => {"key" => "value"}})
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should allow listing resources by public ids" do
|
61
|
+
resources = @api.resources_by_ids(["api_test", "api_test2"], :tags => true, :context => true)["resources"]
|
62
|
+
resources.length.should == 2
|
63
|
+
resources.find{|resource| resource["public_id"] == "api_test"}.should_not be_blank
|
64
|
+
resources.map{|resource| resource["tags"]}.should include(["api_test_tag"])
|
65
|
+
resources.map{|resource| resource["context"]}.should include({"custom" => {"key" => "value"}})
|
54
66
|
end
|
55
67
|
|
56
68
|
it "should allow get resource metadata" do
|
data/spec/uploader_spec.rb
CHANGED
@@ -75,4 +75,36 @@ describe Cloudinary::Uploader do
|
|
75
75
|
result = Cloudinary::Uploader.upload("spec/logo.png", use_filename: true, unique_filename: false)
|
76
76
|
result["public_id"].should == "logo"
|
77
77
|
end
|
78
|
+
|
79
|
+
it "should allow whitelisted formats if allowed_formats", :allowed=>true do
|
80
|
+
result = Cloudinary::Uploader.upload("spec/logo.png", allowed_formats: ["png"])
|
81
|
+
result["format"].should == "png"
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should prevent non whitelisted formats from being uploaded if allowed_formats is specified", :allowed=>true do
|
85
|
+
lambda{Cloudinary::Uploader.upload("spec/logo.png", allowed_formats: ["jpg"])}.should raise_error
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should allow non whitelisted formats if type is specified and convert to that type", :allowed=>true do
|
89
|
+
result = Cloudinary::Uploader.upload("spec/logo.png", allowed_formats: ["jpg"], format: "jpg")
|
90
|
+
result["format"].should == "jpg"
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should allow sending face coordinates" do
|
94
|
+
coordinates = [[120, 30, 109, 150], [121, 31, 110, 151]]
|
95
|
+
result = Cloudinary::Uploader.upload("spec/logo.png", {face_coordinates: coordinates, faces: true})
|
96
|
+
result["faces"].should == coordinates
|
97
|
+
|
98
|
+
different_coordinates = [[122, 32, 111, 152]]
|
99
|
+
Cloudinary::Uploader.explicit(result["public_id"], {face_coordinates: different_coordinates, faces: true, type: "upload"})
|
100
|
+
info = Cloudinary::Api.resource(result["public_id"], {faces: true})
|
101
|
+
info["faces"].should == different_coordinates
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should allow sending context" do
|
105
|
+
context = {"caption" => "some caption", "alt" => "alternative"}
|
106
|
+
result = Cloudinary::Uploader.upload("spec/logo.png", {:context => context})
|
107
|
+
info = Cloudinary::Api.resource(result["public_id"], {:context => true})
|
108
|
+
info["context"].should == {"custom" => context}
|
109
|
+
end
|
78
110
|
end
|
data/spec/utils_spec.rb
CHANGED
@@ -12,7 +12,7 @@ describe Cloudinary::Utils do
|
|
12
12
|
config.cname = nil
|
13
13
|
config.cdn_subdomain = false
|
14
14
|
config.api_key = "1234"
|
15
|
-
config.api_secret = "
|
15
|
+
config.api_secret = "b"
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
@@ -439,4 +439,25 @@ describe Cloudinary::Utils do
|
|
439
439
|
Cloudinary::Utils.cloudinary_url(source).should == "http://res.cloudinary.com/test123/image/upload/#{target}"
|
440
440
|
end
|
441
441
|
end
|
442
|
+
|
443
|
+
it "should correctly sign URLs", :signed => true do
|
444
|
+
options = {version: 1234, transformation: {crop: "crop", width: 10, height: 20}, sign_url: true}
|
445
|
+
expected = "http://res.cloudinary.com/test123/image/upload/s--MaRXzoEC--/c_crop,h_20,w_10/v1234/image.jpg"
|
446
|
+
actual = Cloudinary::Utils.cloudinary_url("image.jpg", options)
|
447
|
+
actual.should == expected
|
448
|
+
|
449
|
+
options = {version: 1234, sign_url: true}
|
450
|
+
expected = "http://res.cloudinary.com/test123/image/upload/s--ZlgFLQcO--/v1234/image.jpg"
|
451
|
+
actual = Cloudinary::Utils.cloudinary_url("image.jpg", options)
|
452
|
+
actual.should == expected
|
453
|
+
|
454
|
+
options = {transformation: {crop: "crop", width: 10, height: 20}, sign_url: true}
|
455
|
+
expected = "http://res.cloudinary.com/test123/image/upload/s--Ai4Znfl3--/c_crop,h_20,w_10/image.jpg"
|
456
|
+
actual = Cloudinary::Utils.cloudinary_url("image.jpg", options)
|
457
|
+
actual.should == expected
|
458
|
+
|
459
|
+
expected = "http://res.cloudinary.com/test123/image/fetch/s--_GAUclyB--/v1234/http://google.com/path/to/image.png"
|
460
|
+
actual = Cloudinary::Utils.cloudinary_url("http://google.com/path/to/image.png", type: "fetch", version: 1234, sign_url: true)
|
461
|
+
actual.should == expected
|
462
|
+
end
|
442
463
|
end
|
metadata
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cloudinary
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.67
|
5
|
+
prerelease:
|
5
6
|
platform: ruby
|
6
7
|
authors:
|
7
8
|
- Nadav Soferman
|
@@ -10,46 +11,52 @@ authors:
|
|
10
11
|
autorequire:
|
11
12
|
bindir: bin
|
12
13
|
cert_chain: []
|
13
|
-
date:
|
14
|
+
date: 2014-01-09 00:00:00.000000000 Z
|
14
15
|
dependencies:
|
15
16
|
- !ruby/object:Gem::Dependency
|
17
|
+
name: rest-client
|
16
18
|
requirement: !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
17
20
|
requirements:
|
18
21
|
- - ! '>='
|
19
22
|
- !ruby/object:Gem::Version
|
20
23
|
version: '0'
|
21
24
|
type: :runtime
|
22
25
|
prerelease: false
|
23
|
-
name: rest-client
|
24
26
|
version_requirements: !ruby/object:Gem::Requirement
|
27
|
+
none: false
|
25
28
|
requirements:
|
26
29
|
- - ! '>='
|
27
30
|
- !ruby/object:Gem::Version
|
28
31
|
version: '0'
|
29
32
|
- !ruby/object:Gem::Dependency
|
33
|
+
name: aws_cf_signer
|
30
34
|
requirement: !ruby/object:Gem::Requirement
|
35
|
+
none: false
|
31
36
|
requirements:
|
32
37
|
- - ! '>='
|
33
38
|
- !ruby/object:Gem::Version
|
34
39
|
version: '0'
|
35
40
|
type: :runtime
|
36
41
|
prerelease: false
|
37
|
-
name: aws_cf_signer
|
38
42
|
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
none: false
|
39
44
|
requirements:
|
40
45
|
- - ! '>='
|
41
46
|
- !ruby/object:Gem::Version
|
42
47
|
version: '0'
|
43
48
|
- !ruby/object:Gem::Dependency
|
49
|
+
name: rspec
|
44
50
|
requirement: !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
45
52
|
requirements:
|
46
53
|
- - ! '>='
|
47
54
|
- !ruby/object:Gem::Version
|
48
55
|
version: '0'
|
49
56
|
type: :development
|
50
57
|
prerelease: false
|
51
|
-
name: rspec
|
52
58
|
version_requirements: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
53
60
|
requirements:
|
54
61
|
- - ! '>='
|
55
62
|
- !ruby/object:Gem::Version
|
@@ -114,26 +121,27 @@ files:
|
|
114
121
|
homepage: http://cloudinary.com
|
115
122
|
licenses:
|
116
123
|
- MIT
|
117
|
-
metadata: {}
|
118
124
|
post_install_message:
|
119
125
|
rdoc_options: []
|
120
126
|
require_paths:
|
121
127
|
- lib
|
122
128
|
required_ruby_version: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
123
130
|
requirements:
|
124
131
|
- - ! '>='
|
125
132
|
- !ruby/object:Gem::Version
|
126
133
|
version: '0'
|
127
134
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
135
|
+
none: false
|
128
136
|
requirements:
|
129
137
|
- - ! '>='
|
130
138
|
- !ruby/object:Gem::Version
|
131
139
|
version: '0'
|
132
140
|
requirements: []
|
133
141
|
rubyforge_project: cloudinary
|
134
|
-
rubygems_version:
|
142
|
+
rubygems_version: 1.8.24
|
135
143
|
signing_key:
|
136
|
-
specification_version:
|
144
|
+
specification_version: 3
|
137
145
|
summary: Client library for easily using the Cloudinary service
|
138
146
|
test_files:
|
139
147
|
- spec/api_spec.rb
|
checksums.yaml
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
---
|
2
|
-
!binary "U0hBMQ==":
|
3
|
-
metadata.gz: !binary |-
|
4
|
-
NjljOWM1ZTk5ODJmZDAyMzc3Y2Y0MGU0OGY0NTE5NTI5N2FkZjA3OA==
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
MmFiZjlmNzJjMDQwZDI4YzUzZmJkZjA0NjRjMzk0MzI2YzVhNDk1Yw==
|
7
|
-
!binary "U0hBNTEy":
|
8
|
-
metadata.gz: !binary |-
|
9
|
-
MWNkY2Y0MzQ1YjljZWM4OTYwZjkxNWY0ZGI1OWRmNjAwOWZlZjRkZTgxOGFm
|
10
|
-
NmI3YjVhMDJlM2Y2MGJmYjk0NmFiNjVkMmI2NzkxNjM3NmViNTdkM2ZhNDc2
|
11
|
-
MTE5MzQ1MjM0ZTY5OGJiMmU0NDliYzBhNDI4N2I0YTY2ZDNmMTM=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
ZTk2ZGUwMTA5MjYyZmFkMWEzZmIzMTQ4NTQ5MjdhMzliMjk5YmQzNzNhZDhh
|
14
|
-
NTBiNGM0MDcyZWVhOGMzODk5NDQ2ZTcxMWI3MTFlMDkzZDkyNTYzOGM5NDI5
|
15
|
-
Yzc4Yjc1MmQ0ZGUxMTcwNDViNjI0ZmUyMTk4NTM2Njg0NDMyMjA=
|