ungulate 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -2,8 +2,20 @@
2
2
 
3
3
  According to Wikipedia, this can mean "hoofed animal". Camels have hooves.
4
4
 
5
- This is a simple queue runner that expects a YAML-encoded job description for RMagick. Documentation: read the code, for now.
5
+ This is a gem for uploading and processing images using an Amazon Web Services stack.
6
+
7
+ It comes with a few goodies:
8
+
9
+ * ungulate_server.rb - simple queue runner that expects a YAML-encoded job description for RMagick
10
+ * Ungulate::FileUpload - a model for e.g. Rails that does some cryptography stuff - example to follow
11
+
12
+ And some planned goodies for the future:
13
+
14
+ * A view helper for Rails that makes it easy to use Ungulate::FileUpload
6
15
 
16
+ == Installation
17
+ gem install ungulate
18
+
7
19
  == Note on Patches/Pull Requests
8
20
 
9
21
  * Fork the project.
data/Rakefile CHANGED
@@ -13,6 +13,7 @@ begin
13
13
  gem.add_dependency "activesupport", ">= 2.3.5"
14
14
  gem.add_dependency "right_aws", ">= 1.10.0"
15
15
  gem.add_dependency "rmagick", ">= 2.12.2"
16
+ gem.add_dependency "mime-types", ">= 1.16"
16
17
  gem.add_development_dependency "rspec", ">= 1.2.9"
17
18
  gem.add_development_dependency "cucumber", ">= 0.6.2"
18
19
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.0.2
@@ -1,35 +1,41 @@
1
1
  require 'active_support'
2
- require 'hmac/sha1'
3
2
  class Ungulate::FileUpload
4
3
  attr_accessor(
5
- :access_key_id,
6
4
  :bucket_url,
7
5
  :key,
8
- :policy,
6
+ :policy
7
+ )
8
+
9
+ cattr_accessor(
10
+ :access_key_id,
11
+ :queue_name,
9
12
  :secret_access_key
10
13
  )
11
14
 
12
15
  def initialize(params)
13
- self.access_key_id = params[:access_key_id]
14
16
  self.bucket_url = params[:bucket_url]
15
17
  self.key = params[:key]
16
18
  self.policy = params[:policy]
17
- self.secret_access_key = params[:secret_access_key]
18
19
  end
19
20
 
20
21
  def acl
21
22
  condition 'acl'
22
23
  end
23
24
 
25
+ def condition(key)
26
+ conditions.find {|condition| condition.first == key}.second
27
+ end
28
+
24
29
  def conditions
25
30
  @conditions ||=
26
- ActiveSupport::JSON.decode(@policy_json)['conditions'].
27
- map {|condition| condition.to_a.flatten}
31
+ @policy_ruby['conditions'].map {|condition| condition.to_a.flatten}
28
32
  end
29
33
 
30
- def policy=(json)
31
- @policy_json = json
32
- @policy = Base64.encode64(json).gsub("\n", '')
34
+ def policy=(policy)
35
+ @policy_ruby = policy
36
+ @policy_ruby['expiration'].utc
37
+ policy_json = ActiveSupport::JSON.encode(@policy_ruby)
38
+ @policy = Base64.encode64(policy_json).gsub("\n", '')
33
39
  end
34
40
 
35
41
  def success_action_redirect
@@ -37,14 +43,10 @@ class Ungulate::FileUpload
37
43
  end
38
44
 
39
45
  def signature
40
- sha1 = HMAC::SHA1.new(secret_access_key)
41
- sha1 << policy
42
- Base64.encode64(sha1.digest).strip
43
- end
44
-
45
- protected
46
-
47
- def condition(key)
48
- conditions.find {|condition| condition.first == key}.second
46
+ Base64.encode64(
47
+ OpenSSL::HMAC.digest(OpenSSL::Digest::Digest.new('sha1'),
48
+ secret_access_key,
49
+ policy)
50
+ ).gsub("\n", '')
49
51
  end
50
52
  end
data/lib/ungulate.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'rubygems'
2
2
  require 'right_aws'
3
3
  require 'RMagick'
4
+ require 'mime/types'
4
5
 
5
6
  module Ungulate
6
7
  def self.logger
@@ -71,7 +72,11 @@ module Ungulate
71
72
  processed_versions.each do |version, image|
72
73
  version_key = version_key version
73
74
  @logger.info "Storing #{version} @ #{version_key}"
74
- bucket.put(version_key, image.to_blob, {}, 'public-read')
75
+ bucket.put(version_key,
76
+ image.to_blob,
77
+ {},
78
+ 'public-read',
79
+ {'Content-Type' => MIME::Types.type_for(image.format).to_s})
75
80
  end
76
81
  end
77
82
 
@@ -3,29 +3,34 @@ require 'ungulate/file_upload'
3
3
 
4
4
  module Ungulate
5
5
  describe FileUpload do
6
- subject do
6
+ before do
7
+ @expiration = 10.hours.from_now
7
8
  @bucket_url = "http://images.bob.com/"
8
- @access_key_id = "asdf"
9
9
  @key = "new-file"
10
10
 
11
- @policy = '{ "expiration": "2007-12-01T12:00:00.000Z",
12
- "conditions": [
13
- {"bucket": "johnsmith" },
14
- ["starts-with", "$key", "user/eric/"],
15
- {"acl": "public-read" },
16
- {"success_action_redirect": "http://johnsmith.s3.amazonaws.com/successful_upload.html" },
17
- ["starts-with", "$Content-Type", "image/"],
18
- {"x-amz-meta-uuid": "14365123651274"},
19
- ["starts-with", "$x-amz-meta-tag", ""]
20
- ]
21
- }
22
- '
11
+ @policy = {
12
+ "expiration" => @expiration,
13
+ "conditions" => [
14
+ {"bucket" => "johnsmith" },
15
+ ["starts-with", "$key", "user/eric/"],
16
+ {"acl" => "public-read" },
17
+ {"success_action_redirect" => "http://johnsmith.s3.amazonaws.com/successful_upload.html" },
18
+ ["starts-with", "$Content-Type", "image/"],
19
+ {"x-amz-meta-uuid" => "14365123651274"},
20
+ ["starts-with", "$x-amz-meta-tag", ""]
21
+ ]
22
+ }
23
+
24
+ @access_key_id = "asdf"
23
25
  @secret_access_key = 'uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o'
26
+ FileUpload.access_key_id = @access_key_id
27
+ FileUpload.secret_access_key = @secret_access_key
28
+ FileUpload.queue_name = 'some-queue-name'
29
+ end
24
30
 
31
+ subject do
25
32
  FileUpload.new(
26
33
  :bucket_url => @bucket_url,
27
- :access_key_id => @access_key_id,
28
- :secret_access_key => @secret_access_key,
29
34
  :policy => @policy,
30
35
  :key => @key
31
36
  )
@@ -44,15 +49,72 @@ module Ungulate
44
49
  ] }
45
50
  its(:access_key_id) { should == @access_key_id }
46
51
  its(:key) { should == @key }
52
+ its(:queue_name) { should == 'some-queue-name' }
47
53
  its(:success_action_redirect) { should == 'http://johnsmith.s3.amazonaws.com/successful_upload.html' }
48
- its(:signature) { should == '4lCsX4TTdC/69HTJE7RWwEdJFgk=' }
49
- its(:policy) { should == 'eyAiZXhwaXJhdGlvbiI6ICIyMDA3LTEyLTAxVDEyOjAwOjAwLjAwMFoiLAogICJjb25kaXRpb25zIjogWwogICAgeyJidWNrZXQiOiAiam9obnNtaXRoIiB9LAogICAgWyJzdGFydHMtd2l0aCIsICIka2V5IiwgInVzZXIvZXJpYy8iXSwKICAgIHsiYWNsIjogInB1YmxpYy1yZWFkIiB9LAogICAgeyJzdWNjZXNzX2FjdGlvbl9yZWRpcmVjdCI6ICJodHRwOi8vam9obnNtaXRoLnMzLmFtYXpvbmF3cy5jb20vc3VjY2Vzc2Z1bF91cGxvYWQuaHRtbCIgfSwKICAgIFsic3RhcnRzLXdpdGgiLCAiJENvbnRlbnQtVHlwZSIsICJpbWFnZS8iXSwKICAgIHsieC1hbXotbWV0YS11dWlkIjogIjE0MzY1MTIzNjUxMjc0In0sCiAgICBbInN0YXJ0cy13aXRoIiwgIiR4LWFtei1tZXRhLXRhZyIsICIiXQogIF0KfQo=' }
54
+
55
+ describe "condition" do
56
+ before do
57
+ subject.stub(:conditions).
58
+ and_return([ ['colour', 'blue'], ['predicate', 'subject', 'object'] ])
59
+ end
60
+
61
+ it "should return the value of a tuple" do
62
+ subject.condition('colour').should == 'blue'
63
+ end
64
+ end
50
65
 
51
66
  describe "conditions" do
52
67
  it "should memoize" do
53
68
  subject.instance_variable_set('@conditions', :cache)
54
69
  subject.conditions.should == :cache
55
70
  end
71
+
72
+ it "should convert mixed hash and array policy to nested arrays" do
73
+ subject.
74
+ instance_variable_set('@policy_ruby',
75
+ {
76
+ 'conditions' => [
77
+ {'colour' => 'blue'},
78
+ ['predicate', 'subject', 'object']
79
+ ]
80
+ })
81
+ subject.conditions.should == [ ['colour', 'blue'], ['predicate', 'subject', 'object'] ]
82
+ end
83
+ end
84
+
85
+ describe "policy=" do
86
+ it "should store the ruby version for later use" do
87
+ subject.policy = @policy
88
+ subject.instance_variable_get('@policy_ruby').should_not be_blank
89
+ end
90
+
91
+ it "should store the base64 encoded JSON" do
92
+ subject # load subject without stubs
93
+
94
+ ActiveSupport::JSON.stub(:encode).with(@policy).and_return(:some_json)
95
+ Base64.stub(:encode64).with(:some_json).and_return("ENCODED\nLINE\nLINE")
96
+ subject.policy = @policy
97
+ subject.policy.should == "ENCODEDLINELINE"
98
+ end
99
+
100
+ it "should ensure the expiration is utc" do
101
+ @expiration.should_receive(:utc).at_least(:once)
102
+ subject.policy = @policy
103
+ end
104
+ end
105
+
106
+ describe "signature" do
107
+ before do
108
+ subject.stub(:policy).and_return(:policy)
109
+ @sha1 = mock('SHA1')
110
+ OpenSSL::Digest::Digest.stub(:new).with('sha1').and_return(@sha1)
111
+ OpenSSL::HMAC.stub(:digest).with(@sha1, @secret_access_key, :policy).and_return(:digest)
112
+ Base64.stub(:encode64).with(:digest).and_return("str\nipme\n")
113
+ end
114
+
115
+ it "should return the stripped base64 encoded digest" do
116
+ subject.signature.should == "stripme"
117
+ end
56
118
  end
57
119
  end
58
120
  end
@@ -193,8 +193,10 @@ module Ungulate
193
193
  describe :process do
194
194
  subject do
195
195
  job = Job.new
196
- @big = mock('Image', :to_blob => 'bigdata')
197
- @little = mock('Image', :to_blob => 'littledata')
196
+ @big = mock('Image', :to_blob => 'bigdata', :format => 'JPEG')
197
+ @little = mock('Image', :to_blob => 'littledata', :format => 'JPEG')
198
+ @mime_type = mock('MimeType', :to_s => 'image/jpeg')
199
+ MIME::Types.stub(:type_for).with('JPEG').and_return(@mime_type)
198
200
  job.stub(:processed_versions).and_return([[:big, @big], [:little, @little]])
199
201
  job.stub(:bucket).and_return(@bucket)
200
202
  job.stub(:version_key).with(:big).and_return('path/to/someimage_big.jpg')
@@ -208,11 +210,13 @@ module Ungulate
208
210
  @bucket.should_receive(:put).with('path/to/someimage_big.jpg',
209
211
  'bigdata',
210
212
  {},
211
- 'public-read')
213
+ 'public-read',
214
+ {'Content-Type' => 'image/jpeg'})
212
215
  @bucket.should_receive(:put).with('path/to/someimage_little.jpg',
213
216
  'littledata',
214
217
  {},
215
- 'public-read')
218
+ 'public-read',
219
+ {'Content-Type' => 'image/jpeg'})
216
220
  end
217
221
 
218
222
  context "empty array" do
data/ungulate.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{ungulate}
8
- s.version = "0.0.1"
8
+ s.version = "0.0.2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Andrew Bruce"]
12
- s.date = %q{2010-04-08}
12
+ s.date = %q{2010-04-11}
13
13
  s.default_executable = %q{ungulate_server.rb}
14
14
  s.description = %q{WIP}
15
15
  s.email = %q{andrew@camelpunch.com}
@@ -60,12 +60,14 @@ Gem::Specification.new do |s|
60
60
  s.add_runtime_dependency(%q<activesupport>, [">= 2.3.5"])
61
61
  s.add_runtime_dependency(%q<right_aws>, [">= 1.10.0"])
62
62
  s.add_runtime_dependency(%q<rmagick>, [">= 2.12.2"])
63
+ s.add_runtime_dependency(%q<mime-types>, [">= 1.16"])
63
64
  s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
64
65
  s.add_development_dependency(%q<cucumber>, [">= 0.6.2"])
65
66
  else
66
67
  s.add_dependency(%q<activesupport>, [">= 2.3.5"])
67
68
  s.add_dependency(%q<right_aws>, [">= 1.10.0"])
68
69
  s.add_dependency(%q<rmagick>, [">= 2.12.2"])
70
+ s.add_dependency(%q<mime-types>, [">= 1.16"])
69
71
  s.add_dependency(%q<rspec>, [">= 1.2.9"])
70
72
  s.add_dependency(%q<cucumber>, [">= 0.6.2"])
71
73
  end
@@ -73,6 +75,7 @@ Gem::Specification.new do |s|
73
75
  s.add_dependency(%q<activesupport>, [">= 2.3.5"])
74
76
  s.add_dependency(%q<right_aws>, [">= 1.10.0"])
75
77
  s.add_dependency(%q<rmagick>, [">= 2.12.2"])
78
+ s.add_dependency(%q<mime-types>, [">= 1.16"])
76
79
  s.add_dependency(%q<rspec>, [">= 1.2.9"])
77
80
  s.add_dependency(%q<cucumber>, [">= 0.6.2"])
78
81
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 1
9
- version: 0.0.1
8
+ - 2
9
+ version: 0.0.2
10
10
  platform: ruby
11
11
  authors:
12
12
  - Andrew Bruce
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-04-08 00:00:00 +01:00
17
+ date: 2010-04-11 00:00:00 +01:00
18
18
  default_executable: ungulate_server.rb
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -60,9 +60,22 @@ dependencies:
60
60
  type: :runtime
61
61
  version_requirements: *id003
62
62
  - !ruby/object:Gem::Dependency
63
- name: rspec
63
+ name: mime-types
64
64
  prerelease: false
65
65
  requirement: &id004 !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ segments:
70
+ - 1
71
+ - 16
72
+ version: "1.16"
73
+ type: :runtime
74
+ version_requirements: *id004
75
+ - !ruby/object:Gem::Dependency
76
+ name: rspec
77
+ prerelease: false
78
+ requirement: &id005 !ruby/object:Gem::Requirement
66
79
  requirements:
67
80
  - - ">="
68
81
  - !ruby/object:Gem::Version
@@ -72,11 +85,11 @@ dependencies:
72
85
  - 9
73
86
  version: 1.2.9
74
87
  type: :development
75
- version_requirements: *id004
88
+ version_requirements: *id005
76
89
  - !ruby/object:Gem::Dependency
77
90
  name: cucumber
78
91
  prerelease: false
79
- requirement: &id005 !ruby/object:Gem::Requirement
92
+ requirement: &id006 !ruby/object:Gem::Requirement
80
93
  requirements:
81
94
  - - ">="
82
95
  - !ruby/object:Gem::Version
@@ -86,7 +99,7 @@ dependencies:
86
99
  - 2
87
100
  version: 0.6.2
88
101
  type: :development
89
- version_requirements: *id005
102
+ version_requirements: *id006
90
103
  description: WIP
91
104
  email: andrew@camelpunch.com
92
105
  executables: