s3lurp 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +152 -0
- data/Rakefile +1 -0
- data/lib/s3lurp.rb +51 -0
- data/lib/s3lurp/railtie.rb +8 -0
- data/lib/s3lurp/version.rb +3 -0
- data/lib/s3lurp/view_helpers.rb +126 -0
- data/s3lurp.gemspec +26 -0
- data/spec/s3lurp_spec.rb +137 -0
- data/spec/spec_helper.rb +35 -0
- data/spec/support/config/s3.yml +4 -0
- metadata +150 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Lukas Eklund
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
# s3lurp - Browser Uploads Direct to S3
|
2
|
+
|
3
|
+
direct s3 upload Rails form helper
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 's3lurp'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install s3lurp
|
18
|
+
|
19
|
+
### Configuration
|
20
|
+
|
21
|
+
S3lurp has many options that can be configured globally or passed
|
22
|
+
to the helper via a hash.
|
23
|
+
|
24
|
+
#### AWS S3 Setup
|
25
|
+
|
26
|
+
There are three options required for buckets that are not public-write:
|
27
|
+
|
28
|
+
* `s3_bucket` - The name of the bucket where files go
|
29
|
+
* `s3_access_key` - This is your AWS Access Key ID
|
30
|
+
* `s3_secret_ley` - Your AWS Secret Accss Key
|
31
|
+
|
32
|
+
|
33
|
+
These three options can be set via a yaml config file, an initializer, or ENV vars.
|
34
|
+
|
35
|
+
|
36
|
+
ENV['S3_BUCKET']
|
37
|
+
ENV['S3_ACCESS_KEY']
|
38
|
+
ENV['S3_SECRET_KEY']
|
39
|
+
|
40
|
+
Another way to set up these options is to us an initializer.
|
41
|
+
|
42
|
+
In config/initializers/s3lurp.rb
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
S3lurp.configure do |config|
|
46
|
+
config.s3_bucket = "bucket_of_holding"
|
47
|
+
config.s3_access_key = "some_acces_key"
|
48
|
+
config.s3_secret_key = "keep_it_secret"
|
49
|
+
```
|
50
|
+
|
51
|
+
Finally you can use use a yaml file to load the configuration.
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
# config/initializers/s3lurp.rb
|
55
|
+
S3lurp.congigure do |config|
|
56
|
+
config.file = 's3lurp.yml'
|
57
|
+
end
|
58
|
+
# config/s3lurp.yml
|
59
|
+
development:
|
60
|
+
s3_bucket: "dev_bucket"
|
61
|
+
s3_access_key: "dev_key"
|
62
|
+
s3_secret_key: "dev_secret"
|
63
|
+
production:
|
64
|
+
s3_bucket: "prod_bucket"
|
65
|
+
s3_access_key: "prod_key"
|
66
|
+
s3_secret_key: "prod_secret"
|
67
|
+
```
|
68
|
+
|
69
|
+
Using a yaml conifg file allows you to use different settings for different
|
70
|
+
environments. Note: It's not necessary to provide environment based settings. The
|
71
|
+
yaml can just be a set of key/value pairs without any grouping by environment.
|
72
|
+
|
73
|
+
#### S3lurp Config Example
|
74
|
+
|
75
|
+
Here is an exmaple of how to configure s3lurp using Heroku.
|
76
|
+
|
77
|
+
Setup your ENV variables for heroku and for local use.
|
78
|
+
For more on Heroku config see here: https://devcenter.heroku.com/articles/config-vars
|
79
|
+
|
80
|
+
```
|
81
|
+
$ heroku config:add S3_KEY=asdfg12345 S3_SECRET=qwertyu0987622`
|
82
|
+
$ export S3_KEY=asdfg12345
|
83
|
+
$ export S3_SECRET=qwertyu0987622
|
84
|
+
```
|
85
|
+
|
86
|
+
Set up some defaults with an initialzer
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
# config/initializers/s3lurp.rb
|
90
|
+
S3lurp.congigure do |config|
|
91
|
+
config.acl = 'public-read'
|
92
|
+
config.minutes_valid = '600'
|
93
|
+
config.max_file_size = 10.megabytes
|
94
|
+
config.min_file_size = 1024
|
95
|
+
end
|
96
|
+
```
|
97
|
+
|
98
|
+
And now in your view you can call
|
99
|
+
|
100
|
+
s3_direct_form_tag({:key => 'photos/uuid/${filename}'})
|
101
|
+
|
102
|
+
This will generate a complete form with a file input and a submit tag. The form
|
103
|
+
will contain all the necessary hidden fields to perform a direct upload to S3.
|
104
|
+
|
105
|
+
#### Configuration Options
|
106
|
+
|
107
|
+
Many of these options correspond to the HTML form fields that AWS accepts. This documentation will
|
108
|
+
be helpful: http://docs.aws.amazon.com/AmazonS3/latest/dev/HTTPPOSTForms.html
|
109
|
+
|
110
|
+
All of these can be congured in an initializer, a yaml config file, or passed directly
|
111
|
+
to the helper in a hash.
|
112
|
+
|
113
|
+
| Option | Description |
|
114
|
+
|--------------------------|-------------|
|
115
|
+
|__:file__ | Name of yaml file located in the config directory. Contains any of the options listed in this table. Should be set inside a configuration block via an initializer. |
|
116
|
+
|__:s3\_bucket__ | AWS S3 bucket name where files will stored. Can also be configured via ENV['S3_BUCKET']. __Required__|
|
117
|
+
|__:s3\_access\_key__ | AWS Access Key. Can also be configured via ENV['S3_ACCESS_KEY']. __Required for buckets that are not public-write.__|
|
118
|
+
|__:s3\_secret\_key__ | AWS AWS Secret Accss Key. Can also be configured via ENV['S3_SECRET_KEY']. __Required for buckets that are not public-write.__|
|
119
|
+
|__:key__ | This is the key for the S3 object. To use the filename of the upload, use the vairable ${filename} (see example). __Required__|
|
120
|
+
|__:acl__ | Sepecies an S3 access control list. Valid values: `private` `public-read` `public-read-write` `authenticated-read` `bucket-owner-read` `bucket-owner-full-control`. _Default_: `private` |
|
121
|
+
|__:cache\_control__ | Refer to [S3 PUT Object documentation](http://docs.aws.amazon.com/AmazonS3/2006-03-01/API/RESTObjectPUT.html)|
|
122
|
+
|__:content\_disposition__ | Refer to [S3 PUT Object documentation](http://docs.aws.amazon.com/AmazonS3/2006-03-01/API/RESTObjectPUT.html)|
|
123
|
+
|__:content\_encoding__ | Refer to [S3 PUT Object documentation](http://docs.aws.amazon.com/AmazonS3/2006-03-01/API/RESTObjectPUT.html)|
|
124
|
+
|__:expires__ | Refer to [S3 PUT Object documentation](http://docs.aws.amazon.com/AmazonS3/2006-03-01/API/RESTObjectPUT.html)|
|
125
|
+
|__:content\_type__ | A standard MIME type describing the format of the contents. _Default_: `binary/octet-stream`. Note: S3 will not automatically determine the content\_type.|
|
126
|
+
|__:success\_action\_redirect__| The URL to which a client is redirected after a successful upload. S3 will append the bucket, key, and etag as query parameters to the URL |
|
127
|
+
|__:success\_action\_status__| HTTP status code returned upon successful upload if success_action_redirect is not set. _Default:_ 204. |
|
128
|
+
|__:min\_file\_size__ | Size in bytes of minimum allowed file size _Default:_ 0 |
|
129
|
+
|__:max\_file\_size__ | Size in bytes of maximum allowed file size _Default:_ 10485760 |
|
130
|
+
|__:amz\_meta\_tags__ | Hash of additional metadata to be stored with the object. Stored on S3 as `x-amz-meta-#{key} = #{value}` |
|
131
|
+
|__:minutes\_valid__ | Length of time in minutes that the generated form is valid. _Default:_ 360 |
|
132
|
+
|__:form\_html\_options__ | Hash of additional options that is passed to the form_tag contructor. |
|
133
|
+
|__:file\_field\_tag\_accept__ | Sets the accept parameter of the file field tag. [?](http://www.w3.org/TR/html-markup/input.file.html#input.file.attrs.accept) |
|
134
|
+
|__:submit\_tag__ | HTML string containing code for the input or button that will handle form submission. This is optional and if not included a basic submit tag will be generated for the form. |
|
135
|
+
|__:submit\_tag\_value__ | Override the value of the standard generated submit tag. _Default:_ "Upload" |
|
136
|
+
|__:submit\_tag\_options__ | Hash of options passed to the submit_tag generator. |
|
137
|
+
|
138
|
+
|
139
|
+
### Examples
|
140
|
+
|
141
|
+
coming soon.
|
142
|
+
|
143
|
+
## Credits
|
144
|
+
|
145
|
+
With inspiration from:
|
146
|
+
|
147
|
+
* [d2s3](https://github.com/mwilliams/d2s3)
|
148
|
+
* [Sinatra-S3-Direct-Upload](https://github.com/waynehoover/Sinatra-S3-Direct-Upload)
|
149
|
+
|
150
|
+
## License
|
151
|
+
|
152
|
+
Copyright © 2013 Lukas Eklund, released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/s3lurp.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 's3lurp/version'
|
2
|
+
require 's3lurp/view_helpers'
|
3
|
+
require 's3lurp/railtie' if defined? ::Rails::Railtie
|
4
|
+
|
5
|
+
module S3lurp
|
6
|
+
VALID_CONFIG_KEYS = [
|
7
|
+
:s3_bucket, :s3_access_key, :s3_secret_key, :acl, :cache_control,
|
8
|
+
:content_type, :content_disposition, :content_encoding, :expires,
|
9
|
+
:success_action_redirect, :success_action_status,
|
10
|
+
:min_file_size, :max_file_size,
|
11
|
+
:amz_meta_tags, :minutes_valid,
|
12
|
+
:form_html_options, :file_field_tag_accept,
|
13
|
+
:submit_tag, :submit_tag_value, :submit_tag_options,
|
14
|
+
:file, :key].freeze
|
15
|
+
class << self
|
16
|
+
attr_accessor :config
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.configure
|
20
|
+
self.config ||= Configuration.new
|
21
|
+
yield(config)
|
22
|
+
if config.file
|
23
|
+
loaded_conf = YAML.load_file(Rails.root.join("config", config.file).to_s)
|
24
|
+
env_conf = loaded_conf[Rails.env] || loaded_conf
|
25
|
+
VALID_CONFIG_KEYS.each do |key|
|
26
|
+
config.send("#{key.to_s}=", env_conf[key.to_s])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.reset_config
|
32
|
+
self.config = nil
|
33
|
+
end
|
34
|
+
|
35
|
+
class Configuration
|
36
|
+
attr_accessor *VALID_CONFIG_KEYS
|
37
|
+
|
38
|
+
def initialize
|
39
|
+
@s3_bucket = ENV['S3_BUCKET'] || "S3_BUCKET"
|
40
|
+
@s3_access_key = ENV['S3_ACCESS_KEY'] || "S3_KEY"
|
41
|
+
@s3_secret_key = ENV['S3_SECRET_KEY'] || "S3_SECRET"
|
42
|
+
@min_file_size = 0
|
43
|
+
@max_file_size = 10485760
|
44
|
+
@minutes_valid = 360
|
45
|
+
@form_html_options = {}
|
46
|
+
@submit_tag_options = {}
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'openssl'
|
3
|
+
require 'digest/sha1'
|
4
|
+
|
5
|
+
module S3lurp
|
6
|
+
module ViewHelpers
|
7
|
+
HIDDEN_FIELD_MAP= {
|
8
|
+
:key => 'key',
|
9
|
+
:s3_access_key => 'AWSAccessKeyId',
|
10
|
+
:acl => 'acl',
|
11
|
+
:cache_control => 'Cache-Control',
|
12
|
+
:content_type => 'Content-Type',
|
13
|
+
:content_disposition => 'Content-Disposition',
|
14
|
+
:content_encoding => 'Content-Encoding',
|
15
|
+
:expires => 'Expires',
|
16
|
+
:success_action_redirect => 'success_action_redirect',
|
17
|
+
:success_action_status => 'success_action_status'
|
18
|
+
}
|
19
|
+
NON_FIELD_OPTIONS = %w( s3_bucket s3_secret_key
|
20
|
+
max_file_size min_file_size
|
21
|
+
amz_meta_tags minutes_valid
|
22
|
+
form_html_options file_field_tag_accept
|
23
|
+
submit_tag submit_tag_value submit_tag_options).map(&:to_sym)
|
24
|
+
|
25
|
+
def s3_direct_form_tag(opt = {})
|
26
|
+
options = (NON_FIELD_OPTIONS + HIDDEN_FIELD_MAP.keys).each_with_object({}) do |i, h|
|
27
|
+
h[i] = opt[i] || S3lurp.config.send(i)
|
28
|
+
end
|
29
|
+
|
30
|
+
# configurable fields the field map is formed as {:configuration_name => "input_field_name"}
|
31
|
+
hidden_fields = HIDDEN_FIELD_MAP.each_with_object({}) do |(k,v), h|
|
32
|
+
h[k] = options[k] unless options[k].nil? || options[k].blank?
|
33
|
+
end
|
34
|
+
|
35
|
+
amz_meta_tags = options[:amz_meta_tags].is_a?(Hash) ? s3_generate_amz_meta_tags(options[:amz_meta_tags]) : {}
|
36
|
+
|
37
|
+
# generate an expiration date for the policy
|
38
|
+
minutes = Integer(options[:minutes_valid]) rescue 360
|
39
|
+
expiration_date = minutes.minutes.from_now.utc.strftime('%Y-%m-%dT%H:%M:%S.000Z')
|
40
|
+
|
41
|
+
security_fields = {}
|
42
|
+
if hidden_fields[:s3_access_key] # only generate security fields when necessary
|
43
|
+
security_fields[:policy] = Base64.encode64(
|
44
|
+
s3_generate_policy(
|
45
|
+
hidden_fields.clone,
|
46
|
+
{ :meta_tags => amz_meta_tags,
|
47
|
+
:s3_bucket => options[:s3_bucket],
|
48
|
+
:expiration => expiration_date,
|
49
|
+
:min_file_size => options[:min_file_size],
|
50
|
+
:max_file_size => options[:max_file_size]
|
51
|
+
}
|
52
|
+
)).gsub(/\n/,'')
|
53
|
+
security_fields[:signature] = Base64.encode64(
|
54
|
+
OpenSSL::HMAC.digest(
|
55
|
+
OpenSSL::Digest::Digest.new('sha1'),
|
56
|
+
options[:s3_secret_key], security_fields[:policy])
|
57
|
+
).gsub(/\n/,'')
|
58
|
+
end
|
59
|
+
|
60
|
+
amz_meta_tags.merge! security_fields
|
61
|
+
submit = s3_generate_submit_tag(options)
|
62
|
+
file = s3_generate_file_field_tag(options)
|
63
|
+
form_tag("http://s3.amazonaws.com/#{options[:s3_bucket]}", {:authenticity_token => false, :method => 'POST', :multipart => true}.merge(options[:form_html_options])) do
|
64
|
+
(
|
65
|
+
hidden_fields.map{|k,v| hidden_field_tag(HIDDEN_FIELD_MAP[k],v, {:id => nil})}.join.html_safe +
|
66
|
+
amz_meta_tags.map{|k,v| hidden_field_tag(k,v,{:id => nil})}.join.html_safe +
|
67
|
+
field_set_tag(nil,:class=>"s3lurp_file") {file} +
|
68
|
+
field_set_tag(nil,:class=>"s3lurp_submit") {submit.html_safe}
|
69
|
+
)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def s3_generate_policy(fields = {}, options = {})
|
74
|
+
fields.delete(:s3_access_key)
|
75
|
+
conditions = [
|
76
|
+
{ :bucket => options[:s3_bucket]},
|
77
|
+
['content-length-range', options[:min_file_size], options[:max_file_size]],
|
78
|
+
['starts-with', '$utf8', ""]
|
79
|
+
]
|
80
|
+
HIDDEN_FIELD_MAP.each do |field, field_name|
|
81
|
+
next unless fields[field]
|
82
|
+
case field
|
83
|
+
when :key
|
84
|
+
key = fields[field].gsub(/\/?\$\{filename\}\/?/,'')
|
85
|
+
conditions.push ["starts-with", "$key", key]
|
86
|
+
else
|
87
|
+
conditions.push ({ field_name => fields[field] })
|
88
|
+
end
|
89
|
+
end
|
90
|
+
if options[:meta_tags]
|
91
|
+
conditions = conditions + options[:meta_tags].map{|k,v| {k => v}}
|
92
|
+
end
|
93
|
+
policy = {
|
94
|
+
"expiration" => options[:expiration],
|
95
|
+
"conditions" => conditions
|
96
|
+
}.to_json
|
97
|
+
end
|
98
|
+
|
99
|
+
def s3_generate_amz_meta_tags(meta = {})
|
100
|
+
meta.each_with_object({}) do |(k,v), hash|
|
101
|
+
hash[%(x-amz-meta-#{k})] = v
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def s3_generate_submit_tag(opt = {})
|
106
|
+
opt[:submit_tag_options].update(:name => nil)
|
107
|
+
if opt[:submit_tag]
|
108
|
+
opt[:submit_tag]
|
109
|
+
elsif opt[:submit_tag_value]
|
110
|
+
submit_tag(opt[:submit_tag_value], opt[:submit_tag_options])
|
111
|
+
else
|
112
|
+
submit_tag("Upload", opt[:submit_tag_options])
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def s3_generate_file_field_tag(opt ={})
|
117
|
+
if opt[:file_field_tag_accept]
|
118
|
+
file_field_tag('file', :accept => opt[:file_field_tag_accept], :class => 's3lurp_file_tag')
|
119
|
+
else
|
120
|
+
file_field_tag('file', :class => 's3lurp_file_tag')
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
data/s3lurp.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 's3lurp/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "s3lurp"
|
8
|
+
spec.version = S3lurp::VERSION
|
9
|
+
spec.authors = ["Lukas Eklund"]
|
10
|
+
spec.email = ["leklund@gmail.com"]
|
11
|
+
spec.description = %q{s3lurp - Browser uploads direct to Amazon S3}
|
12
|
+
spec.summary = %q{ActionView::Helper to generate a form tag for direct uploads to S3. Configurable via ENV or yml}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency "rspec"
|
24
|
+
spec.add_development_dependency 'actionpack'
|
25
|
+
spec.add_development_dependency 'activesupport'
|
26
|
+
end
|
data/spec/s3lurp_spec.rb
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
require 's3lurp'
|
4
|
+
|
5
|
+
ActionView::Base.send(:include, S3lurp::ViewHelpers)
|
6
|
+
|
7
|
+
|
8
|
+
describe S3lurp::ViewHelpers do
|
9
|
+
before do
|
10
|
+
ENV.clear
|
11
|
+
S3lurp.reset_config
|
12
|
+
end
|
13
|
+
view = ActionView::Base.new
|
14
|
+
|
15
|
+
it "should return a form with a minimum set of hidden fields for public buckets" do
|
16
|
+
S3lurp.configure do |config|
|
17
|
+
config.s3_access_key = nil
|
18
|
+
config.s3_secret_key = nil
|
19
|
+
end
|
20
|
+
form = view.s3_direct_form_tag({:key => '/files/s3lurp/lib/s3lurp.rb'})
|
21
|
+
(!!form.match(/<form.*?>/)).should be_true
|
22
|
+
form.should include(%(name="key"), %(type="hidden"))
|
23
|
+
form.should include(%(name="file"), %(type="file"))
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should return a form with a policy and signature and my meta tags" do
|
27
|
+
S3lurp.configure do |config|
|
28
|
+
config.s3_bucket = "bucket_o_stuff"
|
29
|
+
config.s3_access_key = 'oingoboingo'
|
30
|
+
config.s3_secret_key = "qwerty5678_"
|
31
|
+
end
|
32
|
+
form = view.s3_direct_form_tag({
|
33
|
+
:key => '/some/key.pl',
|
34
|
+
:acl => 'public-read',
|
35
|
+
:success_action_redirect => 'http://foobar.com/thanks',
|
36
|
+
:success_action_status => 204,
|
37
|
+
:content_disposition => "attachment",
|
38
|
+
:min_file_size => 1024,
|
39
|
+
:max_file_size => 6291456,
|
40
|
+
:minutes_valid => 333,
|
41
|
+
:amz_meta_tags => {
|
42
|
+
:foo => "bar",
|
43
|
+
:parent_id => 42
|
44
|
+
},
|
45
|
+
:form_html_options => {:class => "myclass", :id => "s3lurp_form"}
|
46
|
+
})
|
47
|
+
(!!form.match(/<form.*?>/)).should be_true
|
48
|
+
form.should include(%(class="myclass"))
|
49
|
+
form.should include(%(id="s3lurp_form"))
|
50
|
+
form.should include(%(name="key"), %(value="/some/key.pl"))
|
51
|
+
form.should include(%(name="AWSAccessKeyId"), %(value="oingoboingo"))
|
52
|
+
form.should include(%(name="file"), %(type="file"))
|
53
|
+
form.should include(%(name="policy"), %(type="hidden"))
|
54
|
+
form.should include(%(name="x-amz-meta-foo"), %(value="bar"))
|
55
|
+
form.should include(%(name="x-amz-meta-parent_id"), %(value="42"))
|
56
|
+
form.should include(%(name="Content-Disposition"), %(type="hidden"), %(value="attachment"))
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should return valid json from the generate policy method and should have the keys I send it' do
|
61
|
+
json = view.s3_generate_policy({:key => "/foo/bar/${filename}", :acl => 'public-read'},
|
62
|
+
{:bucket => 'mybucket',
|
63
|
+
:expiration => "2013-03-14T21:16:51.000Z"})
|
64
|
+
(!!(JSON.parse(json) rescue nil)).should be_true
|
65
|
+
j = JSON.parse(json)
|
66
|
+
j["expiration"].should == "2013-03-14T21:16:51.000Z"
|
67
|
+
key_cond = j["conditions"].select{|a| a[1] == '$key'}.first
|
68
|
+
key_cond[2].should == "/foo/bar"
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should return a submit tag or return the submit tag passed' do
|
72
|
+
view.s3_generate_submit_tag({:submit_tag_value => "zootboot", :submit_tag_options => {}})\
|
73
|
+
.should == %(<input type="submit" value="zootboot" />)
|
74
|
+
view.s3_generate_submit_tag({:submit_tag_options => {:class => "noway"}})\
|
75
|
+
.should == %(<input class="noway" type="submit" value="Upload" />)
|
76
|
+
view.s3_generate_submit_tag({:submit_tag_value => "zootboot", :submit_tag_options => {:class => "noway"}})\
|
77
|
+
.should == %(<input class="noway" type="submit" value="zootboot" />)
|
78
|
+
view.s3_generate_submit_tag({:submit_tag => %(<input type=submit class="button" id="upload-button">), :submit_tag_options => {}})\
|
79
|
+
.should == %(<input type=submit class="button" id="upload-button">)
|
80
|
+
view.s3_generate_submit_tag({:submit_tag_options => {}})\
|
81
|
+
.should == %(<input type="submit" value="Upload" />)
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should generate file field tag with and without accept=' do
|
85
|
+
view.s3_generate_file_field_tag().should_not include("accept")
|
86
|
+
view.s3_generate_file_field_tag({:file_field_tag_accept => "image/*"}).should include('accept="image/*"')
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
describe S3lurp do
|
93
|
+
def random_string
|
94
|
+
rand(36**8).to_s(36)
|
95
|
+
end
|
96
|
+
before do
|
97
|
+
S3lurp.reset_config
|
98
|
+
ENV.clear
|
99
|
+
@bucket = random_string
|
100
|
+
@key = random_string
|
101
|
+
@secret = random_string
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'should configure with options' do
|
105
|
+
S3lurp.configure do |config|
|
106
|
+
config.s3_bucket = @bucket
|
107
|
+
config.s3_access_key = @key
|
108
|
+
config.s3_secret_key = @secret
|
109
|
+
end
|
110
|
+
S3lurp.config.s3_bucket.should == @bucket
|
111
|
+
S3lurp.config.s3_access_key.should == @key
|
112
|
+
S3lurp.config.s3_secret_key.should == @secret
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'should should always use ENV first for config' do
|
116
|
+
ENV['S3_BUCKET'] = @bucket
|
117
|
+
ENV['S3_ACCESS_KEY'] = @key
|
118
|
+
ENV['S3_SECRET_KEY'] = @secret
|
119
|
+
S3lurp.configure do |config|
|
120
|
+
# nothing
|
121
|
+
end
|
122
|
+
S3lurp.config.s3_bucket.should == @bucket
|
123
|
+
S3lurp.config.s3_access_key.should == @key
|
124
|
+
S3lurp.config.s3_secret_key.should == @secret
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'should configure from a yml file' do
|
129
|
+
S3lurp.configure do |config|
|
130
|
+
config.file = 's3.yml'
|
131
|
+
end
|
132
|
+
S3lurp.config.s3_bucket.should == 'yml_bucket'
|
133
|
+
S3lurp.config.s3_access_key.should == 'yml_key'
|
134
|
+
S3lurp.config.s3_secret_key.should == 'yml_secret'
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'active_support'
|
3
|
+
require 'active_support/core_ext/numeric'
|
4
|
+
require 'action_view'
|
5
|
+
require 'pathname'
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
9
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
10
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
11
|
+
# loaded once.
|
12
|
+
#
|
13
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
14
|
+
RSpec.configure do |config|
|
15
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
16
|
+
config.run_all_when_everything_filtered = true
|
17
|
+
config.filter_run :focus
|
18
|
+
|
19
|
+
# Run specs in random order to surface order dependencies. If you find an
|
20
|
+
# order dependency and want to debug it, you can fix the order by providing
|
21
|
+
# the seed, which is printed after each run.
|
22
|
+
# --seed 1234
|
23
|
+
config.order = 'random'
|
24
|
+
end
|
25
|
+
|
26
|
+
require File.expand_path(File.dirname(__FILE__) + "/../lib/s3lurp")
|
27
|
+
|
28
|
+
#some dummy Rails
|
29
|
+
class Rails
|
30
|
+
class << self
|
31
|
+
attr_accessor :env, :root
|
32
|
+
end
|
33
|
+
@env = 'development'
|
34
|
+
@root = Pathname.new(File.expand_path(File.dirname(__FILE__) + "/support"))
|
35
|
+
end
|
metadata
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: s3lurp
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Lukas Eklund
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-03-19 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.3'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.3'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: actionpack
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: activesupport
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
description: s3lurp - Browser uploads direct to Amazon S3
|
95
|
+
email:
|
96
|
+
- leklund@gmail.com
|
97
|
+
executables: []
|
98
|
+
extensions: []
|
99
|
+
extra_rdoc_files: []
|
100
|
+
files:
|
101
|
+
- .gitignore
|
102
|
+
- .rspec
|
103
|
+
- Gemfile
|
104
|
+
- LICENSE.txt
|
105
|
+
- README.md
|
106
|
+
- Rakefile
|
107
|
+
- lib/s3lurp.rb
|
108
|
+
- lib/s3lurp/railtie.rb
|
109
|
+
- lib/s3lurp/version.rb
|
110
|
+
- lib/s3lurp/view_helpers.rb
|
111
|
+
- s3lurp.gemspec
|
112
|
+
- spec/s3lurp_spec.rb
|
113
|
+
- spec/spec_helper.rb
|
114
|
+
- spec/support/config/s3.yml
|
115
|
+
homepage: ''
|
116
|
+
licenses:
|
117
|
+
- MIT
|
118
|
+
post_install_message:
|
119
|
+
rdoc_options: []
|
120
|
+
require_paths:
|
121
|
+
- lib
|
122
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
123
|
+
none: false
|
124
|
+
requirements:
|
125
|
+
- - ! '>='
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: '0'
|
128
|
+
segments:
|
129
|
+
- 0
|
130
|
+
hash: -3173245167068990906
|
131
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
132
|
+
none: false
|
133
|
+
requirements:
|
134
|
+
- - ! '>='
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: '0'
|
137
|
+
segments:
|
138
|
+
- 0
|
139
|
+
hash: -3173245167068990906
|
140
|
+
requirements: []
|
141
|
+
rubyforge_project:
|
142
|
+
rubygems_version: 1.8.25
|
143
|
+
signing_key:
|
144
|
+
specification_version: 3
|
145
|
+
summary: ActionView::Helper to generate a form tag for direct uploads to S3. Configurable
|
146
|
+
via ENV or yml
|
147
|
+
test_files:
|
148
|
+
- spec/s3lurp_spec.rb
|
149
|
+
- spec/spec_helper.rb
|
150
|
+
- spec/support/config/s3.yml
|