s3_file_field 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 43c8582febac6a41acc7a7a6659ed960dd421401
4
+ data.tar.gz: 721a25cdfb745e5c28dabece3f4e0a7ec80126f7
5
+ SHA512:
6
+ metadata.gz: b62187a0b2aa25f71cd286447cfdf6bf0b5682993ec0d7d0a66469f5aeab3fcf77ea6b5f0cdfd5cdc78bd7b9342d7c2a5cad0027e1b21e55a868b49d70c7d8d9
7
+ data.tar.gz: 862e28d624869c3d534fb467d22005559042812f222e72f21b32046a96e40fae302e9b9363f211fc7c512f7eab5a0084138d561295a7b711d7349c9f221d09e2
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Wayne
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,137 @@
1
+ # S3 File Field
2
+
3
+ Stand-alone file field for S3 Direct Upload working with Rails nested forms.
4
+
5
+ Works as an extension of [jQuery File Upload](http://blueimp.github.io/jQuery-File-Upload/) JavaScript plugin and supports IE 7-10.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 's3_direct_upload'
13
+ ```
14
+
15
+ Then add a new initalizer with your AWS credentials:
16
+
17
+ **config/initalizers/s3_file_field.rb**
18
+ ```ruby
19
+ S3FileField.config do |c|
20
+ c.access_key_id = ENV['AWS_ACCESS_KEY_ID']
21
+ c.secret_access_key = ENV['AWS_SECRET_ACCESS_KEY']
22
+ c.bucket = ENV['AWS_BUCKET']
23
+ end
24
+ ```
25
+
26
+ Make sure your AWS S3 CORS Settings for your bucket look like this:
27
+ ```xml
28
+ <CORSConfiguration>
29
+ <CORSRule>
30
+ <AllowedOrigin>*</AllowedOrigin>
31
+ <AllowedMethod>GET</AllowedMethod>
32
+ <AllowedMethod>POST</AllowedMethod>
33
+ <AllowedMethod>PUT</AllowedMethod>
34
+ <AllowedHeader>*</AllowedHeader>
35
+ </CORSRule>
36
+ </CORSConfiguration>
37
+ ```
38
+
39
+ In production the AllowedOrigin key should be your base url like `http://example.com`
40
+
41
+ Also ensure you've added `PutObject` and `PutObjectAcl` permission in your bucket policy. Here is mine:
42
+ ```json
43
+ {
44
+ "Version": "2008-10-17",
45
+ "Id": "Policy1372930880859",
46
+ "Statement": [
47
+ {
48
+ "Sid": "Stmt1372930877007",
49
+ "Effect": "Allow",
50
+ "Principal": {
51
+ "AWS": "*"
52
+ },
53
+ "Action": [
54
+ "s3:GetObject",
55
+ "s3:PutObjectAcl",
56
+ "s3:PutObject"
57
+ ],
58
+ "Resource": "arn:aws:s3:::BUCKET_NAME/*"
59
+ }
60
+ ]
61
+ }
62
+ ```
63
+
64
+ Add the following js to your asset pipeline:
65
+
66
+ **application.js.coffee**
67
+ ```coffeescript
68
+ #= require s3_file_field
69
+ ```
70
+
71
+ ## Usage
72
+
73
+ Create a new view that uses the form helper `s3_uploader_form`:
74
+ ```haml
75
+ = form.s3_file_field :movie, :class => 'js-s3_file_field'
76
+ .progress
77
+ .meter{ :style => "width: 0%" }
78
+ ```
79
+
80
+ Then in your application.js.coffee something like:
81
+ ```coffeescript
82
+ ready = ->
83
+ $(".js-s3_file_field").each ->
84
+ id = $(this).attr('id')
85
+ $this = -> $("##{id}")
86
+ $progress = $(this).siblings('.progress').hide()
87
+ $meter = $progress.find('.meter')
88
+ $(this).S3FileField
89
+ add: (e, data) ->
90
+ $progress.show()
91
+ data.submit()
92
+ done: (e, data) ->
93
+ $progress.hide()
94
+ $this().attr(type: 'text', value: data.result.url, readonly: true)
95
+ fail: (e, data) ->
96
+ alert(data.failReason)
97
+ progress: (e, data) ->
98
+ progress = parseInt(data.loaded / data.total * 100, 10)
99
+ $meter.css(width: "#{progress}%")
100
+
101
+ $(document).ready(ready)
102
+ $(document).on('page:load', ready)
103
+ ```
104
+
105
+ Notice that after upload you have to re-fetch file field from DOM by its ID. That's becase
106
+ jQuery File Upload clones it somewhere else and `$(this)` reference points to the original input.
107
+
108
+
109
+ ## Advanced customization
110
+
111
+ You can use any options / API available for jQuery File Upload plugin.
112
+
113
+ After successful upload, you'll find file data in `data.result` field:
114
+
115
+ ```json
116
+ {
117
+ "filepath": "uploads/v3w3qzcb1d78pvi/something.gif",
118
+ "url": "https://foobar.s3.amazonaws.com/uploads/v3w3qzcb1d78pvi/something.gif",
119
+ "filename": "something.gif",
120
+ "filesize": 184387,
121
+ "filetype": "image\/gif",
122
+ "unique_id": "v3w3qzcb1d78pvi"
123
+ }
124
+ ```
125
+
126
+ ## Cleaning old uploads on S3
127
+
128
+ [Check out this article on Lifecycle Configuration](http://docs.aws.amazon.com/AmazonS3/latest/UG/LifecycleConfiguration.html).
129
+
130
+ ## Thanks
131
+
132
+ * [s3_direct_upload](https://github.com/waynehoover/s3_direct_upload)
133
+ * [gallery-jquery-fileupload](https://github.com/railscasts/383-uploading-to-amazon-s3/tree/master/gallery-jquery-fileupload)
134
+
135
+ ## License
136
+
137
+ This repository is MIT-licensed. You are awesome.
@@ -0,0 +1,96 @@
1
+ #= require jquery-fileupload/basic
2
+ #= require jquery-fileupload/vendor/tmpl
3
+
4
+ jQuery.fn.S3FileField = (options) ->
5
+
6
+ # support multiple elements
7
+ if @length > 1
8
+ @each -> $(this).S3Uploader options if @length > 1
9
+ return this
10
+
11
+ $this = this
12
+
13
+ extractOption = (key) ->
14
+ extracted = options[key]
15
+ delete options[key]
16
+ extracted
17
+
18
+ getFormData = (data, form) ->
19
+ formData = undefined
20
+ return data(form) if typeof data is "function"
21
+ return data if $.isArray(data)
22
+ if $.type(data) is "object"
23
+ formData = []
24
+ $.each data, (name, value) ->
25
+ formData.push
26
+ name: name
27
+ value: value
28
+ return formData
29
+ return []
30
+
31
+ url = extractOption('url')
32
+ add = extractOption('add')
33
+ done = extractOption('done')
34
+ fail = extractOption('fail')
35
+ formData = extractOption('formData')
36
+
37
+ delete options['paramName']
38
+ delete options['singleFileUploads']
39
+
40
+ finalFormData = undefined
41
+
42
+ settings =
43
+ # File input name must be "file"
44
+ paramName: 'file'
45
+
46
+ # S3 doesn't support multiple file uploads
47
+ singleFileUploads: true
48
+
49
+ # We don't want to send it to default form url
50
+ url: url || $this.data('url')
51
+
52
+ # For IE <= 9 force iframe transport
53
+ forceIframeTransport: do ->
54
+ userAgent = navigator.userAgent.toLowerCase()
55
+ msie = /msie/.test( userAgent ) && !/opera/.test( userAgent )
56
+ msie_version = parseInt((userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [])[1], 10)
57
+ msie && msie_version <= 9
58
+
59
+ add: (e, data) ->
60
+ data.files[0].unique_id = Math.random().toString(36).substr(2,16)
61
+ if add? then add(e, data) else data.submit()
62
+
63
+ done: (e, data) ->
64
+ data.result = build_content_object $this, data.files[0], data.result
65
+ done(e, data) if done?
66
+
67
+ fail: (e, data) ->
68
+ fail(e, data) if fail?
69
+
70
+ formData: (form) ->
71
+ finalFormData =
72
+ key: $this.data('key').replace('{timestamp}', new Date().getTime()).replace('{unique_id}', @files[0].unique_id)
73
+ 'Content-Type': @files[0].type
74
+ acl: $this.data('acl')
75
+ 'AWSAccessKeyId': $this.data('aws-access-key-id')
76
+ policy: $this.data('policy')
77
+ signature: $this.data('signature')
78
+ success_action_status: "201"
79
+ 'X-Requested-With': 'xhr'
80
+
81
+ getFormData(finalFormData).concat(getFormData(formData))
82
+
83
+ jQuery.extend settings, options
84
+
85
+ build_content_object = ($this, file, result) ->
86
+ domain = settings.url.replace(/\/+$/, '').replace(/^(https?:)?/, 'https:')
87
+ content = {}
88
+ content.filepath = finalFormData['key'].replace('/${filename}', '')
89
+ content.url = domain + '/' + content.filepath + '/' + file.name
90
+ content.filename = file.name
91
+ content.filesize = file.size if 'size' of file
92
+ content.filetype = file.type if 'type' of file
93
+ content.unique_id = file.unique_id if 'unique_id' of file
94
+ content
95
+
96
+ $this.fileupload settings
@@ -0,0 +1,18 @@
1
+ require "singleton"
2
+
3
+ module S3FileField
4
+ class Config
5
+ include Singleton
6
+
7
+ ATTRIBUTES = [:access_key_id, :secret_access_key, :bucket, :prefix_to_clean, :region, :url]
8
+
9
+ attr_accessor *ATTRIBUTES
10
+ end
11
+
12
+ def self.config
13
+ if block_given?
14
+ yield Config.instance
15
+ end
16
+ Config.instance
17
+ end
18
+ end
@@ -0,0 +1,4 @@
1
+ module S3FileField
2
+ class Engine < ::Rails::Engine
3
+ end
4
+ end
@@ -0,0 +1,99 @@
1
+ module S3FileField
2
+ class Error < StandardError; end
3
+
4
+ module FormBuilder
5
+ def s3_file_field(method, options = {})
6
+ self.multipart = true
7
+ @template.s3_file_field(@object_name, method, objectify_options(options))
8
+ end
9
+ end
10
+
11
+ module FormHelper
12
+ def self.included(arg)
13
+ ActionView::Helpers::FormBuilder.send(:include, S3FileField::FormBuilder)
14
+ end
15
+
16
+ def s3_file_field(object_name, method, options = {})
17
+ uploader = S3Uploader.new(options)
18
+ ActionView::Helpers::Tags::FileField.new(
19
+ object_name, method, self,
20
+ options.reverse_merge(uploader.field_options)
21
+ ).render
22
+ end
23
+
24
+ class S3Uploader
25
+ def initialize(options)
26
+ @options = options.reverse_merge(
27
+ aws_access_key_id: S3FileField.config.access_key_id,
28
+ aws_secret_access_key: S3FileField.config.secret_access_key,
29
+ bucket: S3FileField.config.bucket,
30
+ acl: "public-read",
31
+ expiration: 10.hours.from_now.utc.iso8601,
32
+ max_file_size: 500.megabytes,
33
+ key_starts_with: options[:key_starts_with] || "uploads/"
34
+ )
35
+
36
+ unless @options[:aws_access_key_id]
37
+ raise Error.new("Please configure aws_access_key_id option.")
38
+ end
39
+
40
+ unless @options[:aws_secret_access_key]
41
+ raise Error.new("Please configure aws_secret_access_key option.")
42
+ end
43
+
44
+ unless @options[:bucket]
45
+ raise Error.new("Please configure bucket name.")
46
+ end
47
+ end
48
+
49
+ def field_options
50
+ {
51
+ data: {
52
+ :url => url,
53
+ :key => @options[:key] || key,
54
+ :acl => @options[:acl],
55
+ :'aws-access-key-id' => @options[:aws_access_key_id],
56
+ :policy => policy,
57
+ :signature => signature
58
+ }.reverse_merge(@options[:data] || {})
59
+ }
60
+ end
61
+
62
+ def key
63
+ @key ||= "#{@options[:key_starts_with]}{timestamp}-{unique_id}-#{SecureRandom.hex}/${filename}"
64
+ end
65
+
66
+ def url
67
+ "//#{@options[:bucket]}.s3.amazonaws.com/"
68
+ end
69
+
70
+ def policy
71
+ Base64.encode64(policy_data.to_json).gsub("\n", "")
72
+ end
73
+
74
+ def policy_data
75
+ {
76
+ expiration: @options[:expiration],
77
+ conditions: [
78
+ ["starts-with", "$key", @options[:key_starts_with]],
79
+ ["starts-with", "$x-requested-with", ""],
80
+ ["content-length-range", 0, @options[:max_file_size]],
81
+ ["starts-with","$Content-Type",""],
82
+ {bucket: @options[:bucket]},
83
+ {acl: @options[:acl]},
84
+ {success_action_status: "201"}
85
+ ] + (@options[:conditions] || [])
86
+ }
87
+ end
88
+
89
+ def signature
90
+ Base64.encode64(
91
+ OpenSSL::HMAC.digest(
92
+ OpenSSL::Digest::Digest.new('sha1'),
93
+ @options[:aws_secret_access_key], policy
94
+ )
95
+ ).gsub("\n", "")
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,7 @@
1
+ module S3FileField
2
+ class Railtie < Rails::Railtie
3
+ initializer "railtie.configure_rails_initialization" do |app|
4
+ app.middleware.use JQuery::FileUpload::Rails::Middleware
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ module S3FileField
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,13 @@
1
+ require 's3_file_field/version'
2
+ require 'jquery-fileupload-rails'
3
+
4
+ require 'base64'
5
+ require 'openssl'
6
+ require 'digest/sha1'
7
+
8
+ require 's3_file_field/config_aws'
9
+ require 's3_file_field/form_helper'
10
+ require 's3_file_field/railtie'
11
+ require 's3_file_field/engine'
12
+
13
+ ActionView::Base.send(:include, S3FileField::FormHelper)
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: s3_file_field
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Adam Stankiewicz
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-07-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '3.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '3.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: coffee-rails
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: 3.2.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: 3.2.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: sass-rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: 3.2.5
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: 3.2.5
55
+ - !ruby/object:Gem::Dependency
56
+ name: jquery-fileupload-rails
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 0.4.1
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 0.4.1
69
+ - !ruby/object:Gem::Dependency
70
+ name: bundler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '1.3'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '1.3'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Form helper for Direct Uploading to Amazon S3 using CORS and jquery-file-upload
98
+ email:
99
+ - sheerun@sher.pl
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - lib/s3_file_field/config_aws.rb
105
+ - lib/s3_file_field/engine.rb
106
+ - lib/s3_file_field/form_helper.rb
107
+ - lib/s3_file_field/railtie.rb
108
+ - lib/s3_file_field/version.rb
109
+ - lib/s3_file_field.rb
110
+ - app/assets/javascripts/s3_file_field.js.coffee
111
+ - LICENSE
112
+ - README.md
113
+ homepage: ''
114
+ licenses: []
115
+ metadata: {}
116
+ post_install_message:
117
+ rdoc_options: []
118
+ require_paths:
119
+ - lib
120
+ required_ruby_version: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ required_rubygems_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - '>='
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ requirements: []
131
+ rubyforge_project:
132
+ rubygems_version: 2.0.0
133
+ signing_key:
134
+ specification_version: 4
135
+ summary: Form helper for Direct Uploading to Amazon S3 using CORS and jquery-file-upload
136
+ test_files: []