s3-upnow 0.1.7 → 0.2.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 731e98ac15afe2b0944cb3b6669f03a4a7771538
4
- data.tar.gz: 56b0c073f0b216026c4fe532d8febd26639fea5a
3
+ metadata.gz: c130dadc4b2ed0be86811b4b029c7539a3265cd8
4
+ data.tar.gz: a8c1aba09a3f422360bbe1abdc5b58f151a7dab4
5
5
  SHA512:
6
- metadata.gz: b9f9d5f7769adbec1d986daa9d3713ef6addd2d217791a63b449ecd6e2898f36849d60415d5b306eaabafb2367b8169577859687c29116be26d1ab4b510fc206
7
- data.tar.gz: ed9c53695746ca26102c18185583d201ff9c00bb93ffe6a7c9802e50c20f82d53fc42a670b870dc7552690df611cb30170cdf5b9f24ba2e994531b684da58d55
6
+ metadata.gz: f3936e913d8dbeb45fea532dc0c1dbb7d6ce2871b404acfb8b685f8920a473b8bb336f87b525bca0fd18971af5b73c290a75b5bdab9791c8c9e0cf57904fbde0
7
+ data.tar.gz: 136f94792ef3951b6e58212b6a42f460e42fca936bb6efc6c8a7c44c06797aebafefb422be88bf35f4a9adcba794d308bdce7e8d2de42b6cd542b70e136e9165
@@ -0,0 +1,50 @@
1
+ $(document).on 'change', (e) ->
2
+ input = $(e.target)
3
+ if (input.prop('tagName') == "INPUT" && input.prop('type') == "file" && input.data('upnow'))
4
+ return if (!input.prop('files'))
5
+ file = input.prop('files')[0]
6
+ file.unique_id = Math.random().toString(36).substr(2,16)
7
+
8
+ dispatchEvent = (name, detail) ->
9
+ ev = document.createEvent('CustomEvent')
10
+ ev.initCustomEvent(name, true, false, detail)
11
+ input[0].dispatchEvent(ev)
12
+
13
+ if (file)
14
+ url = input.data('url')
15
+ fields = input.data('fields')
16
+
17
+ data = new FormData()
18
+
19
+ if (fields)
20
+ Object.keys(fields).forEach (key) ->
21
+ if key == 'key'
22
+ fields[key] = fields[key]
23
+ .replace('{timestamp}', new Date().getTime())
24
+ .replace('{unique_id}', file.unique_id)
25
+ data.append(key, fields[key])
26
+ data.append('content-type', file.type)
27
+ data.append('file', file)
28
+
29
+ xhr = new XMLHttpRequest()
30
+ xhr.addEventListener('load', (e) ->
31
+ input.removeClass('uploading')
32
+ dispatchEvent('upload:complete', xhr.response)
33
+ if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304)
34
+ key = input.data('key') || $(xhr.response).find('Key').text()
35
+ input.prev().val(key)
36
+ input.removeAttr('name')
37
+ dispatchEvent('upload:success', xhr.response)
38
+ else
39
+ dispatchEvent('upload:failure', xhr.response)
40
+ )
41
+
42
+ xhr.upload.addEventListener('progress', (e) ->
43
+ dispatchEvent('upload:progress', e) if (e.lengthComputable)
44
+ )
45
+
46
+ xhr.open('POST', url, true)
47
+ xhr.send(data)
48
+
49
+ input.addClass('uploading')
50
+ dispatchEvent('upload:start')
@@ -10,4 +10,6 @@ require 's3-upnow/form_helper'
10
10
  require 's3-upnow/engine' if defined?(Rails)
11
11
  require 's3-upnow/railtie' if defined?(Rails)
12
12
 
13
- ActionView::Base.send(:include, S3UpNow::UploadHelper) if defined?(ActionView::Base)
13
+ module S3UpNow
14
+ autoload :Paperclip, 's3-upnow/paperclip'
15
+ end
@@ -1,4 +1,8 @@
1
1
  module S3UpNow
2
2
  class Engine < ::Rails::Engine
3
+ initializer "s3-upnow.setup", before: :load_environment_config do
4
+ ActionView::Base.send(:include, S3UpNow::S3UpNowHelper) if defined?(ActionView::Base)
5
+ ActionView::Helpers::FormBuilder.send(:include, S3UpNow::S3UpNowFieldHelper)
6
+ end
3
7
  end
4
8
  end
@@ -1,97 +1,22 @@
1
+ require 's3-upnow/generator'
2
+
1
3
  module S3UpNow
2
- module UploadHelper
3
- def s3_uploader_form(options = {}, &block)
4
- uploader = S3Uploader.new(options)
5
- form_tag(uploader.url, uploader.form_options) do
6
- uploader.fields.map do |name, value|
7
- hidden_field_tag(name, value)
8
- end.join.html_safe + capture(&block)
9
- end
4
+ module S3UpNowHelper
5
+ def s3_upnow_field(object_name, method, options = {})
6
+ generator = S3UpNow::Generator.new(options)
7
+ options[:data] ||= {}
8
+ options[:data][:upnow] = true
9
+ options[:data][:url] = generator.url
10
+ options[:data][:fields] = generator.fields
11
+ hidden_field(object_name, :"#{method}_s3_key", options.slice(:object)) +
12
+ file_field(object_name, method, options)
10
13
  end
14
+ end
11
15
 
12
- class S3Uploader
13
- def initialize(options)
14
- @key_starts_with = options[:key_starts_with] || "uploads/"
15
- @options = options.reverse_merge(
16
- aws_access_key_id: S3UpNow.config.access_key_id,
17
- aws_secret_access_key: S3UpNow.config.secret_access_key,
18
- bucket: options[:bucket] || S3UpNow.config.bucket,
19
- region: S3UpNow.config.region || "s3",
20
- url: S3UpNow.config.url,
21
- ssl: true,
22
- acl: "public-read",
23
- expiration: 10.hours.from_now.utc.iso8601,
24
- max_file_size: 500.megabytes,
25
- callback_method: "POST",
26
- callback_param: "file",
27
- key_starts_with: @key_starts_with,
28
- key: key
29
- )
30
- end
31
-
32
- def form_options
33
- {
34
- id: @options[:id],
35
- class: @options[:class],
36
- method: "post",
37
- authenticity_token: false,
38
- multipart: true,
39
- data: {
40
- callback_url: @options[:callback_url],
41
- callback_method: @options[:callback_method],
42
- callback_param: @options[:callback_param]
43
- }.reverse_merge(@options[:data] || {})
44
- }
45
- end
46
-
47
- def fields
48
- {
49
- :key => @options[:key] || key,
50
- :acl => @options[:acl],
51
- "AWSAccessKeyId" => @options[:aws_access_key_id],
52
- :policy => policy,
53
- :signature => signature,
54
- :success_action_status => "201",
55
- 'X-Requested-With' => 'xhr'
56
- }
57
- end
58
-
59
- def key
60
- @key ||= "#{@key_starts_with}{timestamp}-{unique_id}-#{SecureRandom.hex}/${filename}"
61
- end
62
-
63
- def url
64
- @options[:url] || "http#{@options[:ssl] ? 's' : ''}://#{@options[:region]}.amazonaws.com/#{@options[:bucket]}/"
65
- end
66
-
67
- def policy
68
- Base64.encode64(policy_data.to_json).gsub("\n", "")
69
- end
70
-
71
- def policy_data
72
- {
73
- expiration: @options[:expiration],
74
- conditions: [
75
- ["starts-with", "$utf8", ""],
76
- ["starts-with", "$key", @options[:key_starts_with]],
77
- ["starts-with", "$x-requested-with", ""],
78
- ["content-length-range", 0, @options[:max_file_size]],
79
- ["starts-with","$content-type", @options[:content_type_starts_with] ||""],
80
- {bucket: @options[:bucket]},
81
- {acl: @options[:acl]},
82
- {success_action_status: "201"}
83
- ] + (@options[:conditions] || [])
84
- }
85
- end
86
-
87
- def signature
88
- Base64.encode64(
89
- OpenSSL::HMAC.digest(
90
- OpenSSL::Digest.new('sha1'),
91
- @options[:aws_secret_access_key], policy
92
- )
93
- ).gsub("\n", "")
94
- end
16
+ module S3UpNowFieldHelper
17
+ def s3_upnow_field(method, options = {})
18
+ self.multipart = true
19
+ @template.s3_upnow_field(@object_name, method, objectify_options(options))
95
20
  end
96
21
  end
97
22
  end
@@ -0,0 +1,74 @@
1
+ # encoding: utf-8
2
+
3
+ module S3UpNow
4
+ class Generator
5
+ def initialize(options)
6
+ @key_starts_with = options[:key_starts_with] || "uploads/"
7
+ @options = options.reverse_merge(
8
+ aws_access_key_id: S3UpNow.config.access_key_id,
9
+ aws_secret_access_key: S3UpNow.config.secret_access_key,
10
+ bucket: options[:bucket] || S3UpNow.config.bucket,
11
+ region: S3UpNow.config.region || "s3",
12
+ url: S3UpNow.config.url,
13
+ ssl: true,
14
+ acl: "public-read",
15
+ expiration: 10.hours.from_now.utc.iso8601,
16
+ max_file_size: 500.megabytes,
17
+ callback_method: "POST",
18
+ callback_param: "file",
19
+ key_starts_with: @key_starts_with,
20
+ key: key
21
+ )
22
+ end
23
+
24
+ def fields
25
+ {
26
+ :utf8 => '✓',
27
+ :key => @options[:key] || key,
28
+ :acl => @options[:acl],
29
+ "AWSAccessKeyId" => @options[:aws_access_key_id],
30
+ :policy => policy,
31
+ :signature => signature,
32
+ :success_action_status => "201",
33
+ 'X-Requested-With' => 'xhr'
34
+ }
35
+ end
36
+
37
+ def key
38
+ @key ||= "#{@key_starts_with}{timestamp}-{unique_id}-#{SecureRandom.hex}/${filename}"
39
+ end
40
+
41
+ def url
42
+ @options[:url] || "http#{@options[:ssl] ? 's' : ''}://#{@options[:region]}.amazonaws.com/#{@options[:bucket]}/"
43
+ end
44
+
45
+ def policy
46
+ Base64.encode64(policy_data.to_json).gsub("\n", "")
47
+ end
48
+
49
+ def policy_data
50
+ {
51
+ expiration: @options[:expiration],
52
+ conditions: [
53
+ ["starts-with", "$utf8", ""],
54
+ ["starts-with", "$key", @options[:key_starts_with]],
55
+ ["starts-with", "$x-requested-with", ""],
56
+ ["content-length-range", 0, @options[:max_file_size]],
57
+ ["starts-with","$content-type", @options[:content_type_starts_with] ||""],
58
+ {bucket: @options[:bucket]},
59
+ {acl: @options[:acl]},
60
+ {success_action_status: "201"}
61
+ ] + (@options[:conditions] || [])
62
+ }
63
+ end
64
+
65
+ def signature
66
+ Base64.encode64(
67
+ OpenSSL::HMAC.digest(
68
+ OpenSSL::Digest.new('sha1'),
69
+ @options[:aws_secret_access_key], policy
70
+ )
71
+ ).gsub("\n", "")
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,61 @@
1
+ module S3UpNow
2
+ module Paperclip
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ base.class_eval do
6
+ private
7
+
8
+ def s3_upnow_attachment(name)
9
+ send(name)
10
+ end
11
+
12
+ def s3_upnow_destination_bucket(name)
13
+ s3_upnow_attachment(name).options[:bucket].call
14
+ end
15
+
16
+ def s3_upnow_destination_path(name)
17
+ s3_upnow_attachment(name).path[1..-1]
18
+ end
19
+
20
+ def s3_upnow_destination_permissions(name)
21
+ s3_upnow_attachment(name).s3_permissions
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ module ClassMethods
28
+ def has_attached_file(name, options = {})
29
+ puts "here"
30
+ self.class_eval do
31
+ attr_accessor "#{name}_s3_key"
32
+
33
+ before_validation "s3_upnow_copy_metadata_from_#{name}".to_sym, unless: "#{name}_s3_key.blank?"
34
+ after_save "s3_upnow_copy_file_from_#{name}".to_sym, unless: "#{name}_s3_key.blank?"
35
+
36
+ private
37
+
38
+ define_method "s3_upnow_copy_metadata_from_#{name}" do
39
+ s3 = AWS::S3.new
40
+ s3_head = s3.buckets[S3UpNow.config.bucket].objects[instance_variable_get("@#{name}_s3_key")].head
41
+
42
+ s3_upnow_attachment(name).clear
43
+ self.send "#{name}_file_name=", File.basename(instance_variable_get("@#{name}_s3_key"))
44
+ self.send "#{name}_file_size=", s3_head.content_length
45
+ self.send "#{name}_content_type=", s3_head.content_type
46
+ self.send "#{name}_updated_at=", s3_head.last_modified
47
+ end
48
+
49
+ define_method "s3_upnow_copy_file_from_#{name}" do
50
+ s3 = AWS::S3.new
51
+ orig_bucket = s3.buckets[S3UpNow.config.bucket]
52
+ orig_object = orig_bucket.objects[instance_variable_get("@#{name}_s3_key")]
53
+ dest_bucket = s3.buckets[s3_upnow_destination_bucket(name)]
54
+ dest_object = dest_bucket.objects[s3_upnow_destination_path(name)]
55
+ dest_object.copy_from(orig_object, acl: s3_upnow_destination_permissions(name))
56
+ end
57
+ end
58
+ super(name, options)
59
+ end
60
+ end
61
+ end
@@ -1,6 +1,9 @@
1
1
  module S3UpNow
2
2
  class Railtie < Rails::Railtie
3
- initializer "railtie.configure_rails_initialization" do |app|
3
+ initializer "railtie.configure_rails_initialization", after: "paperclip.insert_into_active_record" do |app|
4
+ if defined?(ActiveRecord) and defined?(Paperclip)
5
+ ActiveRecord::Base.send(:include, S3UpNow::Paperclip)
6
+ end
4
7
  app.middleware.use JQuery::FileUpload::Rails::Middleware
5
8
  end
6
9
  end
@@ -1,3 +1,3 @@
1
1
  module S3UpNow
2
- VERSION = "0.1.7"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: s3-upnow
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Carlos Eduardo Rodrigues Diógenes
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-21 00:00:00.000000000 Z
11
+ date: 2015-01-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -75,12 +75,14 @@ extra_rdoc_files: []
75
75
  files:
76
76
  - LICENSE
77
77
  - README.md
78
- - app/assets/javascripts/s3_direct_upload.js.coffee
79
- - app/assets/stylesheets/s3_direct_upload_progress_bars.css.scss
78
+ - app/assets/javascripts/s3-upnow.js.coffee
79
+ - app/assets/stylesheets/s3-upnow-progress-bar.css.scss
80
80
  - lib/s3-upnow.rb
81
81
  - lib/s3-upnow/config_aws.rb
82
82
  - lib/s3-upnow/engine.rb
83
83
  - lib/s3-upnow/form_helper.rb
84
+ - lib/s3-upnow/generator.rb
85
+ - lib/s3-upnow/paperclip.rb
84
86
  - lib/s3-upnow/railtie.rb
85
87
  - lib/s3-upnow/version.rb
86
88
  - lib/tasks/s3_upnow.rake
@@ -103,7 +105,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
103
105
  version: '0'
104
106
  requirements: []
105
107
  rubyforge_project:
106
- rubygems_version: 2.2.2
108
+ rubygems_version: 2.4.2
107
109
  signing_key:
108
110
  specification_version: 4
109
111
  summary: Gives a form helper for Rails which allows direct uploads to s3. Based on
@@ -1,173 +0,0 @@
1
- #= require jquery-fileupload/basic
2
- #= require jquery-fileupload/vendor/tmpl
3
-
4
- $ = jQuery
5
-
6
- $.fn.S3Uploader = (options) ->
7
-
8
- # support multiple elements
9
- if @length > 1
10
- @each ->
11
- $(this).S3Uploader options
12
-
13
- return this
14
-
15
- $uploadForm = this
16
-
17
- settings =
18
- path: ''
19
- additional_data: null
20
- before_add: null
21
- remove_completed_progress_bar: true
22
- remove_failed_progress_bar: false
23
- progress_bar_target: null
24
- click_submit_target: null
25
- allow_multiple_files: true
26
-
27
- $.extend settings, options
28
-
29
- current_files = []
30
- forms_for_submit = []
31
- if settings.click_submit_target
32
- settings.click_submit_target.click ->
33
- form.submit() for form in forms_for_submit
34
- false
35
-
36
- setUploadForm = ->
37
- $uploadForm.fileupload
38
-
39
- add: (e, data) ->
40
- file = data.files[0]
41
- file.unique_id = Math.random().toString(36).substr(2,16)
42
-
43
- unless settings.before_add and not settings.before_add(file)
44
- current_files.push data
45
- if $('#template-upload').length > 0
46
- data.context = $($.trim(tmpl("template-upload", file)))
47
- $(data.context).appendTo(settings.progress_bar_target || $uploadForm)
48
- else if !settings.allow_multiple_files
49
- data.context = settings.progress_bar_target
50
- if settings.click_submit_target
51
- if settings.allow_multiple_files
52
- forms_for_submit.push data
53
- else
54
- forms_for_submit = [data]
55
- else
56
- data.submit()
57
-
58
- start: (e) ->
59
- $uploadForm.trigger("s3_uploads_start", [e])
60
-
61
- progress: (e, data) ->
62
- if data.context
63
- progress = parseInt(data.loaded / data.total * 100, 10)
64
- data.context.find('.bar').css('width', progress + '%')
65
-
66
- done: (e, data) ->
67
- content = build_content_object $uploadForm, data.files[0], data.result
68
-
69
- callback_url = $uploadForm.data('callback-url')
70
- if callback_url
71
- content[$uploadForm.data('callback-param')] = content.url
72
-
73
- $.ajax
74
- type: $uploadForm.data('callback-method')
75
- url: callback_url
76
- data: content
77
- beforeSend: ( xhr, settings ) ->
78
- event = $.Event('ajax:beforeSend')
79
- $uploadForm.trigger(event, [xhr, settings])
80
- return event.result
81
- complete: ( xhr, status ) ->
82
- event = $.Event('ajax:complete')
83
- $uploadForm.trigger(event, [xhr, status])
84
- return event.result
85
- success: ( data, status, xhr ) ->
86
- event = $.Event('ajax:success')
87
- $uploadForm.trigger(event, [data, status, xhr])
88
- return event.result
89
- error: ( xhr, status, error ) ->
90
- event = $.Event('ajax:error')
91
- $uploadForm.trigger(event, [xhr, status, error])
92
- return event.result
93
-
94
- data.context.remove() if data.context && settings.remove_completed_progress_bar # remove progress bar
95
- $uploadForm.trigger("s3_upload_complete", [content])
96
-
97
- current_files.splice($.inArray(data, current_files), 1) # remove that element from the array
98
- $uploadForm.trigger("s3_uploads_complete", [content]) unless current_files.length
99
-
100
- fail: (e, data) ->
101
- content = build_content_object $uploadForm, data.files[0], data.result
102
- content.error_thrown = data.errorThrown
103
-
104
- data.context.remove() if data.context && settings.remove_failed_progress_bar # remove progress bar
105
- $uploadForm.trigger("s3_upload_failed", [content])
106
-
107
- formData: (form) ->
108
- data = form.serializeArray()
109
- fileType = ""
110
- if "type" of @files[0]
111
- fileType = @files[0].type
112
- data.push
113
- name: "content-type"
114
- value: fileType
115
-
116
- key = $uploadForm.data("key")
117
- .replace('{timestamp}', new Date().getTime())
118
- .replace('{unique_id}', @files[0].unique_id)
119
- .replace('{extension}', @files[0].name.split('.').pop())
120
-
121
- # substitute upload timestamp and unique_id into key
122
- key_field = $.grep data, (n) ->
123
- n if n.name == "key"
124
-
125
- if key_field.length > 0
126
- key_field[0].value = settings.path + key
127
-
128
- # IE <= 9 doesn't have XHR2 hence it can't use formData
129
- # replace 'key' field to submit form
130
- unless 'FormData' of window
131
- $uploadForm.find("input[name='key']").val(settings.path + key)
132
- data
133
-
134
- build_content_object = ($uploadForm, file, result) ->
135
- content = {}
136
- if result # Use the S3 response to set the URL to avoid character encodings bugs
137
- content.url = $(result).find("Location").text()
138
- content.filepath = $('<a />').attr('href', content.url)[0].pathname
139
- else # IE <= 9 retu rn a null result object so we use the file object instead
140
- domain = $uploadForm.attr('action')
141
- content.filepath = $uploadForm.find('input[name=key]').val().replace('/${filename}', '')
142
- content.url = domain + content.filepath + '/' + encodeURIComponent(file.name)
143
-
144
- content.filename = file.name
145
- content.filesize = file.size if 'size' of file
146
- content.lastModifiedDate = file.lastModifiedDate if 'lastModifiedDate' of file
147
- content.filetype = file.type if 'type' of file
148
- content.unique_id = file.unique_id if 'unique_id' of file
149
- content.relativePath = build_relativePath(file) if has_relativePath(file)
150
- content = $.extend content, settings.additional_data if settings.additional_data
151
- content
152
-
153
- has_relativePath = (file) ->
154
- file.relativePath || file.webkitRelativePath
155
-
156
- build_relativePath = (file) ->
157
- file.relativePath || (file.webkitRelativePath.split("/")[0..-2].join("/") + "/" if file.webkitRelativePath)
158
-
159
- #public methods
160
- @initialize = ->
161
- # Save key for IE9 Fix
162
- $uploadForm.data("key", $uploadForm.find("input[name='key']").val())
163
-
164
- setUploadForm()
165
- this
166
-
167
- @path = (new_path) ->
168
- settings.path = new_path
169
-
170
- @additional_data = (new_data) ->
171
- settings.additional_data = new_data
172
-
173
- @initialize()