ungulate 0.0.1 → 0.0.2

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