s3_multipart 0.0.10.4 → 0.0.10.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +2 -0
- data/app/controllers/s3_multipart/uploads_controller.rb +12 -8
- data/app/models/s3_multipart/upload.rb +15 -7
- data/config/locales/s3_multipart.en.yml +10 -0
- data/lib/s3_multipart/transfer_helpers.rb +50 -18
- data/lib/s3_multipart/uploader.rb +7 -2
- data/lib/s3_multipart/version.rb +1 -1
- data/vendor/assets/javascripts/s3_multipart/lib.js +16 -18
- metadata +23 -40
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d98ae2406219c5a736d33bf323dfb675f2649e18
|
4
|
+
data.tar.gz: 790a0d7b0d2d42765c05474851eaffd773845a10
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c5aec821b693decc4f4d86a4ef4a7fa000dfe3e3a051dc7567c42de585da0a97d466d7193b9b68cfec34e88f40ef62149959f9cacd7ea3b594bf39ad9b093c13
|
7
|
+
data.tar.gz: 3885d74fa41187e425cd4273d73bad593221937368efa238592efa5a31c24b2f781e479db623af403f4c97c940fed06335a2060151bf3a0e72f09a987bfcacfc
|
data/README.md
CHANGED
@@ -6,6 +6,8 @@ Multipart uploading allows files to be split into many chunks and uploaded in pa
|
|
6
6
|
|
7
7
|
## What's New
|
8
8
|
|
9
|
+
**0.0.10.5** - See pull request [16](https://github.com/maxgillett/s3_multipart/pull/16) and [18](https://github.com/maxgillett/s3_multipart/pull/18) for detailed changes.
|
10
|
+
|
9
11
|
**0.0.10.4** - Fixed a race condition that led to incorrect upload progress feedback.
|
10
12
|
|
11
13
|
**0.0.10.3** - Fixed a bug that prevented 5-10mb files from being uploaded correctly.
|
@@ -8,8 +8,9 @@ module S3Multipart
|
|
8
8
|
response = upload.to_json
|
9
9
|
rescue FileTypeError, FileSizeError => e
|
10
10
|
response = {error: e.message}
|
11
|
-
rescue
|
12
|
-
|
11
|
+
rescue => e
|
12
|
+
logger.error "EXC: #{e.message}"
|
13
|
+
response = { error: t("s3_multipart.errors.create") }
|
13
14
|
ensure
|
14
15
|
render :json => response
|
15
16
|
end
|
@@ -26,8 +27,9 @@ module S3Multipart
|
|
26
27
|
def sign_batch
|
27
28
|
begin
|
28
29
|
response = Upload.sign_batch(params)
|
29
|
-
rescue
|
30
|
-
|
30
|
+
rescue => e
|
31
|
+
logger.error "EXC: #{e.message}"
|
32
|
+
response = {error: t("s3_multipart.errors.update")}
|
31
33
|
ensure
|
32
34
|
render :json => response
|
33
35
|
end
|
@@ -36,8 +38,9 @@ module S3Multipart
|
|
36
38
|
def sign_part
|
37
39
|
begin
|
38
40
|
response = Upload.sign_part(params)
|
39
|
-
rescue
|
40
|
-
|
41
|
+
rescue => e
|
42
|
+
logger.error "EXC: #{e.message}"
|
43
|
+
response = {error: t("s3_multipart.errors.update")}
|
41
44
|
ensure
|
42
45
|
render :json => response
|
43
46
|
end
|
@@ -49,8 +52,9 @@ module S3Multipart
|
|
49
52
|
upload = Upload.find_by_upload_id(params[:upload_id])
|
50
53
|
upload.update_attributes(location: response[:location])
|
51
54
|
upload.execute_callback(:complete, session)
|
52
|
-
rescue
|
53
|
-
|
55
|
+
rescue => e
|
56
|
+
logger.error "EXC: #{e.message}"
|
57
|
+
response = {error: t("s3_multipart.errors.complete")}
|
54
58
|
ensure
|
55
59
|
render :json => response
|
56
60
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
module S3Multipart
|
2
2
|
class Upload < ::ActiveRecord::Base
|
3
3
|
extend S3Multipart::TransferHelpers
|
4
|
+
include ActionView::Helpers::NumberHelper
|
4
5
|
|
5
|
-
attr_accessible :key, :upload_id, :name, :location, :uploader, :size
|
6
6
|
before_create :validate_file_type, :validate_file_size
|
7
7
|
|
8
8
|
def self.create(params)
|
@@ -17,7 +17,7 @@ module S3Multipart
|
|
17
17
|
when :begin
|
18
18
|
controller.on_begin_callback.call(self, session) if controller.on_begin_callback
|
19
19
|
when :complete
|
20
|
-
controller.on_complete_callback.call(self, session) if controller.
|
20
|
+
controller.on_complete_callback.call(self, session) if controller.on_complete_callback
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
@@ -26,16 +26,24 @@ module S3Multipart
|
|
26
26
|
def validate_file_size
|
27
27
|
size = self.size
|
28
28
|
limits = deserialize(self.uploader).size_limits
|
29
|
-
|
30
|
-
|
29
|
+
|
30
|
+
if limits.present?
|
31
|
+
if limits.key?(:min) && limits[:min] > size
|
32
|
+
raise FileSizeError, I18n.t("s3_multipart.errors.limits.min", min: number_to_human_size(limits[:min]))
|
33
|
+
end
|
34
|
+
|
35
|
+
if limits.key?(:max) && limits[:max] < size
|
36
|
+
raise FileSizeError, I18n.t("s3_multipart.errors.limits.max", max: number_to_human_size(limits[:max]))
|
37
|
+
end
|
38
|
+
end
|
31
39
|
end
|
32
40
|
|
33
41
|
def validate_file_type
|
34
42
|
ext = self.name.match(/\.([a-zA-Z0-9]+)$/)[1]
|
35
|
-
|
43
|
+
types = deserialize(self.uploader).file_types
|
36
44
|
|
37
|
-
|
38
|
-
raise FileTypeError, "
|
45
|
+
unless types.blank? || types.include?(ext)
|
46
|
+
raise FileTypeError, I18n.t("s3_multipart.errors.types", types: upload.deserialize(upload.uploader).file_types.join(", "))
|
39
47
|
end
|
40
48
|
end
|
41
49
|
|
@@ -0,0 +1,10 @@
|
|
1
|
+
en:
|
2
|
+
s3_multipart:
|
3
|
+
errors:
|
4
|
+
limits:
|
5
|
+
min: "Please choose a larger file (min %{min})"
|
6
|
+
max: "Please choose a smaller file (max %{max})"
|
7
|
+
types: "Please choose a different format (allowed types: %{types})"
|
8
|
+
create: "There was an error initiating the upload"
|
9
|
+
update: "There was an error processing the upload"
|
10
|
+
complete: "There was an error completing the upload"
|
@@ -5,43 +5,45 @@ module S3Multipart
|
|
5
5
|
module TransferHelpers
|
6
6
|
|
7
7
|
def initiate(options)
|
8
|
-
|
9
|
-
unique_name = UUID.generate + real_name.match(/.[A-Za-z0-9]+$/)[0] # clean this up later
|
10
|
-
url = "/#{unique_name}?uploads"
|
8
|
+
url = "/#{unique_name(options)}?uploads"
|
11
9
|
|
12
10
|
headers = {content_type: options[:content_type]}
|
13
|
-
headers[:
|
11
|
+
headers.merge!(options[:headers]) if options.key?(:headers)
|
12
|
+
headers[:authorization], headers[:date] = sign_request verb: 'POST',
|
13
|
+
url: url,
|
14
|
+
content_type: options[:content_type],
|
15
|
+
headers: options[:headers]
|
14
16
|
|
15
|
-
response = Http.post url,
|
17
|
+
response = Http.post url, headers: headers
|
16
18
|
parsed_response_body = XmlSimple.xml_in(response.body)
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
-
|
20
|
+
{ "key" => parsed_response_body["Key"][0],
|
21
|
+
"upload_id" => parsed_response_body["UploadId"][0],
|
22
|
+
"name" => options[:object_name] }
|
21
23
|
end
|
22
24
|
|
23
25
|
def sign_batch(options)
|
24
|
-
parts = options[:content_lengths].split('-').each_with_index.map do |len, i|
|
26
|
+
parts = options[:content_lengths].to_s.split('-').each_with_index.map do |len, i|
|
25
27
|
sign_part(options.merge!({content_length: len, part_number: i+1}))
|
26
28
|
end
|
27
29
|
end
|
28
30
|
|
29
31
|
def sign_part(options)
|
30
32
|
url = "/#{options[:object_name]}?partNumber=#{options[:part_number]}&uploadId=#{options[:upload_id]}"
|
31
|
-
authorization, date = sign_request verb: 'PUT', url: url, content_length: options[:content_length]
|
33
|
+
authorization, date = sign_request verb: 'PUT', url: URI.escape(url), content_length: options[:content_length]
|
32
34
|
|
33
|
-
|
35
|
+
{ authorization: authorization, date: date }
|
34
36
|
end
|
35
37
|
|
36
38
|
def complete(options)
|
37
39
|
options[:content_type] = "application/xml"
|
38
40
|
|
39
|
-
url = "/#{options[:object_name]}?uploadId=#{options[:upload_id]}"
|
41
|
+
url = URI.escape("/#{options[:object_name]}?uploadId=#{options[:upload_id]}")
|
40
42
|
|
41
43
|
body = format_part_list_in_xml(options)
|
42
44
|
headers = { content_type: options[:content_type],
|
43
45
|
content_length: options[:content_length] }
|
44
|
-
|
46
|
+
|
45
47
|
headers[:authorization], headers[:date] = sign_request verb: 'POST', url: url, content_type: options[:content_type]
|
46
48
|
|
47
49
|
response = Http.post url, {headers: headers, body: body}
|
@@ -55,19 +57,49 @@ module S3Multipart
|
|
55
57
|
end
|
56
58
|
|
57
59
|
def sign_request(options)
|
58
|
-
|
59
|
-
time
|
60
|
+
time = Time.now.utc.strftime("%a, %d %b %Y %T %Z")
|
61
|
+
[calculate_authorization_hash(time, options), time]
|
62
|
+
end
|
63
|
+
|
64
|
+
def unique_name(options)
|
65
|
+
url = [UUID.generate, options[:object_name]].join("/")
|
66
|
+
controller = S3Multipart::Uploader.deserialize(options[:uploader])
|
60
67
|
|
61
|
-
|
68
|
+
if controller.mount_point && defined?(CarrierWaveDirect)
|
69
|
+
uploader = controller.model.to_s.classify.constantize.new.send(controller.mount_point)
|
70
|
+
|
71
|
+
if uploader.class.ancestors.include?(CarrierWaveDirect::Uploader)
|
72
|
+
url = uploader.key.sub(/#{Regexp.escape(CarrierWaveDirect::Uploader::FILENAME_WILDCARD)}\z/, options[:object_name])
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
URI.escape(url)
|
62
77
|
end
|
63
78
|
|
64
79
|
private
|
65
80
|
|
66
81
|
def calculate_authorization_hash(time, options)
|
67
82
|
date = String.new(time)
|
68
|
-
|
83
|
+
request_parts = [ options[:verb],
|
84
|
+
"", # optional content md5
|
85
|
+
options[:content_type]]
|
86
|
+
|
87
|
+
headers = options[:headers] || {}
|
88
|
+
|
89
|
+
if from_upload_part?(options) && options[:parts].nil?
|
90
|
+
request_parts << "" # skip date as it's present as an x-amz- header
|
91
|
+
headers["x-amz-date"] = date
|
92
|
+
else
|
93
|
+
request_parts << date
|
94
|
+
end
|
95
|
+
|
96
|
+
if headers.present?
|
97
|
+
canonicalized_headers = headers.keys.sort.inject([]) {|array,k| array.push "#{k}:#{headers[k]}"}.join("\n")
|
98
|
+
request_parts << canonicalized_headers
|
99
|
+
end
|
69
100
|
|
70
|
-
|
101
|
+
request_parts << "/#{Config.instance.bucket_name}#{options[:url]}"
|
102
|
+
unsigned_request = request_parts.join("\n")
|
71
103
|
signature = Base64.strict_encode64(OpenSSL::HMAC.digest('sha1', Config.instance.s3_secret_key, unsigned_request))
|
72
104
|
|
73
105
|
authorization = "AWS" + " " + Config.instance.s3_access_key + ":" + signature
|
@@ -27,13 +27,18 @@ module S3Multipart
|
|
27
27
|
include S3Multipart::Uploader::Callbacks
|
28
28
|
include S3Multipart::Uploader::Validations
|
29
29
|
|
30
|
+
attr_accessor :mount_point, :model
|
31
|
+
|
30
32
|
def self.extended(klass)
|
31
33
|
Uploader.controllers[klass.to_s.to_sym] = Digest::SHA1.hexdigest(klass.to_s)
|
32
34
|
end
|
33
35
|
|
34
|
-
def attach(model)
|
36
|
+
def attach(model, options = {})
|
37
|
+
self.mount_point = options.delete(:using)
|
38
|
+
self.model = model
|
39
|
+
|
35
40
|
S3Multipart::Upload.class_eval do
|
36
|
-
has_one(model)
|
41
|
+
has_one(model, options)
|
37
42
|
end
|
38
43
|
end
|
39
44
|
|
data/lib/s3_multipart/version.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module S3Multipart
|
2
|
-
VERSION = "0.0.10.
|
2
|
+
VERSION = "0.0.10.5"
|
3
3
|
BREAKING_CHANGES = {
|
4
4
|
:"0.0.10.2" => 'Modifications made to the database table used by the gem are now handled by migrations. If you are upgrading versions, run `rails g s3_multipart:install_new_migrations` followed by `rake db:migrate`. Fresh installs do not require subsequent migrations. The current version must now also be passed in to the gem\'s configuration function to alert you of breaking changes. This is done by setting a revision yml variable. See the section regarding the aws.yml file in the readme section below (just before "Getting Started").'
|
5
5
|
}
|
@@ -19,6 +19,7 @@ function S3MP(options) {
|
|
19
19
|
, S3MP = this;
|
20
20
|
|
21
21
|
_.extend(this, options);
|
22
|
+
this.headers = _.object(_.map(options.headers, function(v,k) { return ["x-amz-" + k.toLowerCase(), v] }));
|
22
23
|
|
23
24
|
this.uploadList = [];
|
24
25
|
|
@@ -32,7 +33,7 @@ function S3MP(options) {
|
|
32
33
|
var i = [];
|
33
34
|
function beginUpload(pipes, uploadObj) {
|
34
35
|
var key = uploadObj.key
|
35
|
-
, num_parts = uploadObj.parts.length
|
36
|
+
, num_parts = uploadObj.parts.length;
|
36
37
|
|
37
38
|
if (typeof i[key] === "undefined") {
|
38
39
|
i[key] = 0;
|
@@ -61,6 +62,7 @@ function S3MP(options) {
|
|
61
62
|
var parts, i, ETag;
|
62
63
|
|
63
64
|
parts = uploadObj.parts;
|
65
|
+
finished_part.status = "complete";
|
64
66
|
|
65
67
|
// Append the ETag (in the response header) to the ETags array
|
66
68
|
ETag = finished_part.xhr.getResponseHeader("ETag");
|
@@ -155,12 +157,6 @@ function S3MP(options) {
|
|
155
157
|
}
|
156
158
|
|
157
159
|
_.each(files, function(file, key) {
|
158
|
-
if (file.size < 5000000) {
|
159
|
-
return S3MP.onError({name: "FileSizeError", message: "File size is too small"})
|
160
|
-
// This should still work. The multipart API just can't be used b/c Amazon doesn't allow
|
161
|
-
// multipart file uploads that are less than 5 mb in size.
|
162
|
-
}
|
163
|
-
|
164
160
|
var upload = new Upload(file, S3MP, key);
|
165
161
|
S3MP.uploadList.push(upload);
|
166
162
|
upload.init();
|
@@ -175,6 +171,7 @@ S3MP.prototype.initiateMultipart = function(upload, cb) {
|
|
175
171
|
body = JSON.stringify({ object_name : upload.name,
|
176
172
|
content_type : upload.type,
|
177
173
|
content_size : upload.size,
|
174
|
+
headers : this.headers,
|
178
175
|
uploader : $(this.fileInputElement).data("uploader")
|
179
176
|
});
|
180
177
|
|
@@ -190,7 +187,7 @@ S3MP.prototype.signPartRequests = function(id, object_name, upload_id, parts, cb
|
|
190
187
|
return memo + "-" + part.size;
|
191
188
|
}, parts[0].size);
|
192
189
|
|
193
|
-
url = "s3_multipart/uploads/"+id;
|
190
|
+
url = "/s3_multipart/uploads/"+id;
|
194
191
|
body = JSON.stringify({ object_name : object_name,
|
195
192
|
upload_id : upload_id,
|
196
193
|
content_lengths : content_lengths
|
@@ -203,7 +200,7 @@ S3MP.prototype.signPartRequests = function(id, object_name, upload_id, parts, cb
|
|
203
200
|
S3MP.prototype.completeMultipart = function(uploadObj, cb) {
|
204
201
|
var url, body, xhr;
|
205
202
|
|
206
|
-
url = 's3_multipart/uploads/'+uploadObj.id;
|
203
|
+
url = '/s3_multipart/uploads/'+uploadObj.id;
|
207
204
|
body = JSON.stringify({ object_name : uploadObj.object_name,
|
208
205
|
upload_id : uploadObj.upload_id,
|
209
206
|
content_length : uploadObj.size,
|
@@ -224,7 +221,7 @@ S3MP.prototype.deliverRequest = function(xhr, body, cb) {
|
|
224
221
|
if (response.error) {
|
225
222
|
return self.onError({
|
226
223
|
name: "ServerResponse",
|
227
|
-
message:
|
224
|
+
message: response.error
|
228
225
|
});
|
229
226
|
}
|
230
227
|
cb(response);
|
@@ -406,12 +403,8 @@ function Upload(file, o, key) {
|
|
406
403
|
|
407
404
|
upload.signPartRequests(id, object_name, upload_id, parts, function(response) {
|
408
405
|
_.each(parts, function(part, key) {
|
409
|
-
|
410
|
-
|
411
|
-
xhr.open('PUT', 'http://'+upload.bucket+'.s3.amazonaws.com/'+object_name+'?partNumber='+part.num+'&uploadId='+upload_id, true);
|
412
|
-
xhr.setRequestHeader('x-amz-date', response[key].date);
|
413
|
-
xhr.setRequestHeader('Authorization', response[key].authorization);
|
414
|
-
|
406
|
+
part.date = response[key].date;
|
407
|
+
part.auth = response[key].authorization;
|
415
408
|
// Notify handler that an xhr request has been opened
|
416
409
|
upload.handler.beginUpload(pipes, upload);
|
417
410
|
});
|
@@ -433,6 +426,7 @@ function UploadPart(blob, key, upload) {
|
|
433
426
|
this.size = blob.size;
|
434
427
|
this.blob = blob;
|
435
428
|
this.num = key;
|
429
|
+
this.upload = upload;
|
436
430
|
|
437
431
|
this.xhr = xhr = upload.createXhrRequest();
|
438
432
|
xhr.onload = function() {
|
@@ -442,7 +436,7 @@ function UploadPart(blob, key, upload) {
|
|
442
436
|
upload.handler.onError(upload, part);
|
443
437
|
};
|
444
438
|
xhr.upload.onprogress = _.throttle(function(e) {
|
445
|
-
if (
|
439
|
+
if (e.lengthComputable) {
|
446
440
|
upload.inprogress[key] = e.loaded;
|
447
441
|
}
|
448
442
|
}, 1000);
|
@@ -450,6 +444,10 @@ function UploadPart(blob, key, upload) {
|
|
450
444
|
};
|
451
445
|
|
452
446
|
UploadPart.prototype.activate = function() {
|
447
|
+
this.xhr.open('PUT', 'http://'+this.upload.bucket+'.s3.amazonaws.com/'+this.upload.object_name+'?partNumber='+this.num+'&uploadId='+this.upload.upload_id, true);
|
448
|
+
this.xhr.setRequestHeader('x-amz-date', this.date);
|
449
|
+
this.xhr.setRequestHeader('Authorization', this.auth);
|
450
|
+
|
453
451
|
this.xhr.send(this.blob);
|
454
452
|
this.status = "active";
|
455
453
|
};
|
@@ -463,4 +461,4 @@ return S3MP;
|
|
463
461
|
|
464
462
|
}());
|
465
463
|
|
466
|
-
}(this));
|
464
|
+
}(this));
|
metadata
CHANGED
@@ -1,52 +1,46 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: s3_multipart
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.10.
|
5
|
-
prerelease:
|
4
|
+
version: 0.0.10.5
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Max Gillett
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2014-04-19 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: uuid
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - '>='
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: 2.3.6
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - '>='
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: 2.3.6
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: xml-simple
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - '>='
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: 1.1.2
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - '>='
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: 1.1.2
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: combustion
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
45
|
- - ~>
|
52
46
|
- !ruby/object:Gem::Version
|
@@ -54,7 +48,6 @@ dependencies:
|
|
54
48
|
type: :development
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
52
|
- - ~>
|
60
53
|
- !ruby/object:Gem::Version
|
@@ -62,84 +55,74 @@ dependencies:
|
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: rails
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
|
-
- -
|
59
|
+
- - '>='
|
68
60
|
- !ruby/object:Gem::Version
|
69
61
|
version: '0'
|
70
62
|
type: :development
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
|
-
- -
|
66
|
+
- - '>='
|
76
67
|
- !ruby/object:Gem::Version
|
77
68
|
version: '0'
|
78
69
|
- !ruby/object:Gem::Dependency
|
79
70
|
name: sqlite3
|
80
71
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
72
|
requirements:
|
83
|
-
- -
|
73
|
+
- - '>='
|
84
74
|
- !ruby/object:Gem::Version
|
85
75
|
version: '0'
|
86
76
|
type: :development
|
87
77
|
prerelease: false
|
88
78
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
79
|
requirements:
|
91
|
-
- -
|
80
|
+
- - '>='
|
92
81
|
- !ruby/object:Gem::Version
|
93
82
|
version: '0'
|
94
83
|
- !ruby/object:Gem::Dependency
|
95
84
|
name: rspec
|
96
85
|
requirement: !ruby/object:Gem::Requirement
|
97
|
-
none: false
|
98
86
|
requirements:
|
99
|
-
- -
|
87
|
+
- - '>='
|
100
88
|
- !ruby/object:Gem::Version
|
101
89
|
version: '0'
|
102
90
|
type: :development
|
103
91
|
prerelease: false
|
104
92
|
version_requirements: !ruby/object:Gem::Requirement
|
105
|
-
none: false
|
106
93
|
requirements:
|
107
|
-
- -
|
94
|
+
- - '>='
|
108
95
|
- !ruby/object:Gem::Version
|
109
96
|
version: '0'
|
110
97
|
- !ruby/object:Gem::Dependency
|
111
98
|
name: rspec-rails
|
112
99
|
requirement: !ruby/object:Gem::Requirement
|
113
|
-
none: false
|
114
100
|
requirements:
|
115
|
-
- -
|
101
|
+
- - '>='
|
116
102
|
- !ruby/object:Gem::Version
|
117
103
|
version: '0'
|
118
104
|
type: :development
|
119
105
|
prerelease: false
|
120
106
|
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
none: false
|
122
107
|
requirements:
|
123
|
-
- -
|
108
|
+
- - '>='
|
124
109
|
- !ruby/object:Gem::Version
|
125
110
|
version: '0'
|
126
111
|
- !ruby/object:Gem::Dependency
|
127
112
|
name: capybara
|
128
113
|
requirement: !ruby/object:Gem::Requirement
|
129
|
-
none: false
|
130
114
|
requirements:
|
131
|
-
- -
|
115
|
+
- - '>='
|
132
116
|
- !ruby/object:Gem::Version
|
133
117
|
version: '0'
|
134
118
|
type: :development
|
135
119
|
prerelease: false
|
136
120
|
version_requirements: !ruby/object:Gem::Requirement
|
137
|
-
none: false
|
138
121
|
requirements:
|
139
|
-
- -
|
122
|
+
- - '>='
|
140
123
|
- !ruby/object:Gem::Version
|
141
124
|
version: '0'
|
142
|
-
description:
|
125
|
+
description: 'See github for installation and configuration '
|
143
126
|
email:
|
144
127
|
- max.gillett@gmail.com
|
145
128
|
executables: []
|
@@ -156,6 +139,7 @@ files:
|
|
156
139
|
- app/controllers/s3_multipart/application_controller.rb
|
157
140
|
- app/controllers/s3_multipart/uploads_controller.rb
|
158
141
|
- app/models/s3_multipart/upload.rb
|
142
|
+
- config/locales/s3_multipart.en.yml
|
159
143
|
- config/routes.rb
|
160
144
|
- grunt.js
|
161
145
|
- javascripts/footer.js
|
@@ -281,26 +265,25 @@ files:
|
|
281
265
|
- vendor/assets/javascripts/s3_multipart/lib.min.js
|
282
266
|
homepage: https://github.com/maxgillett/s3_multipart
|
283
267
|
licenses: []
|
268
|
+
metadata: {}
|
284
269
|
post_install_message:
|
285
270
|
rdoc_options: []
|
286
271
|
require_paths:
|
287
272
|
- lib
|
288
273
|
required_ruby_version: !ruby/object:Gem::Requirement
|
289
|
-
none: false
|
290
274
|
requirements:
|
291
|
-
- -
|
275
|
+
- - '>='
|
292
276
|
- !ruby/object:Gem::Version
|
293
277
|
version: '0'
|
294
278
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
295
|
-
none: false
|
296
279
|
requirements:
|
297
|
-
- -
|
280
|
+
- - '>='
|
298
281
|
- !ruby/object:Gem::Version
|
299
282
|
version: '0'
|
300
283
|
requirements: []
|
301
284
|
rubyforge_project:
|
302
|
-
rubygems_version:
|
285
|
+
rubygems_version: 2.0.3
|
303
286
|
signing_key:
|
304
|
-
specification_version:
|
287
|
+
specification_version: 4
|
305
288
|
summary: Upload directly to S3 using multipart uploading
|
306
289
|
test_files: []
|