uppy-s3_multipart 0.3.1 → 1.0.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
  SHA256:
3
- metadata.gz: e12372444e16d107d5c90ec8af0a414ce4be9cb80789104d876ccbcb659f2e47
4
- data.tar.gz: 72b57faaed4df24f0e5614f7b9fe2a9129773bd3dfeba2e34c13929f930df196
3
+ metadata.gz: 127c554611e36c8802a60174dfbd624bab6de29aaa5f1ccdd04b71c2224f108e
4
+ data.tar.gz: 6950b75f85c04b03e973ae9581f59ec8defc4d1be7c5c50080fcd638c71adf97
5
5
  SHA512:
6
- metadata.gz: cc918fcce0cba1544acf9fe92996d81a3afc165c248cafe9ce6c615e1cd6c9d0feef8ec787b4269c0583f2478c7a94467b47964e41fb31aade21e11e569a5a03
7
- data.tar.gz: cf5352bb5dbe444dc748eaa593b311a2545f0d1fdb4a0c2f0f3f364290e3a82acdbd7912536851a951aecc3ff872acb0580fd73cb60daf4af85757c2a32fc89e
6
+ metadata.gz: 292d94dbb74c0efe2108f041207e86a5d46b99d63fb85f4cf2ccc5c252d47c00507b6118bdfd995ee762049fc389705982cfc566ddc1f906b7956185179db1fd
7
+ data.tar.gz: 305fb7fea58a49a3768ebda006c5827b9b3911006087bb61f623a2519b10f5c680a39ab0578db085823963d2046753f3f4b294a4716c3e6e836b3c18173c1999
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Uppy::S3Multipart
2
2
 
3
- Provides a Rack application that implements endpoints for the [AwsS3Multipart]
3
+ Provides a Rack application that implements endpoints for the [aws-s3-multipart]
4
4
  Uppy plugin. This enables multipart uploads directly to S3, which is
5
5
  recommended when dealing with large files, as it allows resuming interrupted
6
6
  uploads.
@@ -10,37 +10,49 @@ uploads.
10
10
  Add the gem to your Gemfile:
11
11
 
12
12
  ```rb
13
- gem "uppy-s3_multipart", "~> 0.2"
13
+ gem "uppy-s3_multipart", "~> 1.0"
14
14
  ```
15
15
 
16
16
  ## Setup
17
17
 
18
- In order to allow direct multipart uploads to your S3 bucket, we need to update
18
+ In order to allow direct multipart uploads to your S3 bucket, you need to update
19
19
  the bucket's CORS configuration. In the AWS S3 Console go to your bucket, click
20
20
  on "Permissions" tab and then on "CORS configuration". There paste in the
21
21
  following:
22
22
 
23
- ```xml
24
- <?xml version="1.0" encoding="UTF-8"?>
25
- <CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
26
- <CORSRule>
27
- <AllowedOrigin>https://my-app.com</AllowedOrigin>
28
- <AllowedMethod>GET</AllowedMethod>
29
- <AllowedMethod>POST</AllowedMethod>
30
- <AllowedMethod>PUT</AllowedMethod>
31
- <MaxAgeSeconds>3000</MaxAgeSeconds>
32
- <AllowedHeader>Authorization</AllowedHeader>
33
- <AllowedHeader>x-amz-date</AllowedHeader>
34
- <AllowedHeader>x-amz-content-sha256</AllowedHeader>
35
- <AllowedHeader>content-type</AllowedHeader>
36
- <ExposeHeader>ETag</ExposeHeader>
37
- </CORSRule>
38
- <CORSRule>
39
- <AllowedOrigin>*</AllowedOrigin>
40
- <AllowedMethod>GET</AllowedMethod>
41
- <MaxAgeSeconds>3000</MaxAgeSeconds>
42
- </CORSRule>
43
- </CORSConfiguration>
23
+ ```json
24
+ [
25
+ {
26
+ "AllowedHeaders": [
27
+ "content-type",
28
+ "x-amz-content-sha256",
29
+ "x-amz-date"
30
+ ],
31
+ "AllowedMethods": [
32
+ "GET",
33
+ "POST",
34
+ "PUT"
35
+ ],
36
+ "AllowedOrigins": [
37
+ "https://my-app.com"
38
+ ],
39
+ "ExposeHeaders": [
40
+ "ETag"
41
+ ],
42
+ "MaxAgeSeconds": 3000
43
+ },
44
+ {
45
+ "AllowedHeaders": [],
46
+ "AllowedMethods": [
47
+ "GET"
48
+ ],
49
+ "AllowedOrigins": [
50
+ "*"
51
+ ],
52
+ "ExposeHeaders": [],
53
+ "MaxAgeSeconds": 3000
54
+ }
55
+ ]
44
56
  ```
45
57
 
46
58
  Replace `https://my-app.com` with the URL to your app (in development you can
@@ -51,11 +63,63 @@ CORS settings to be applied.
51
63
 
52
64
  This gem provides a Rack application that you can mount inside your main
53
65
  application. If you're using [Shrine], you can initialize the Rack application
54
- via the `uppy_s3_multipart` Shrine plugin, otherwise you can initialize it
55
- directly.
66
+ via the [Shrine plugin](#shrine).
67
+
68
+ ### App
69
+
70
+ At its core, you initialize an `Uppy::S3Multipart::App` with an
71
+ `Aws::S3::Bucket` object:
72
+
73
+ ```rb
74
+ require "uppy/s3_multipart"
75
+
76
+ bucket = Aws::S3::Bucket.new(
77
+ name: "my-bucket",
78
+ access_key_id: "...",
79
+ secret_access_key: "...",
80
+ region: "...",
81
+ )
82
+
83
+ UPPY_S3_MULTIPART_APP = Uppy::S3Multipart::App.new(bucket: bucket)
84
+ ```
85
+
86
+ The instance of `Uppy::S3Multipart::App` is a Rack application that can be
87
+ mounted in your router (`config/routes.rb` in Rails). It should be
88
+ mounted at `/s3/multipart`:
89
+
90
+ ```rb
91
+ # config/routes.rb (Rails)
92
+ Rails.application.routes.draw do
93
+ # ...
94
+ mount UPPY_S3_MULTIPART_APP => "/s3/multipart"
95
+ end
96
+ ```
97
+
98
+ This will add the routes that the `aws-s3-multipart` Uppy plugin expects:
99
+
100
+ ```
101
+ POST /s3/multipart
102
+ GET /s3/multipart/:uploadId
103
+ GET /s3/multipart/:uploadId/:partNumber
104
+ POST /s3/multipart/:uploadId/complete
105
+ DELETE /s3/multipart/:uploadId
106
+ ```
107
+
108
+ Since your app will now play the role of Uppy Companion, in your Uppy
109
+ configuration you can point `companionUrl` to your app's URL:
110
+
111
+ ```js
112
+ // ...
113
+ uppy.use(Uppy.AwsS3Multipart, {
114
+ companionUrl: '/',
115
+ })
116
+ ```
56
117
 
57
118
  ### Shrine
58
119
 
120
+ If you're using Shrine, you can use the `uppy_s3_multipart` Shrine plugin that
121
+ ships with this gem to simplify the setup.
122
+
59
123
  In your Shrine initializer load the `uppy_s3_multipart` plugin:
60
124
 
61
125
  ```rb
@@ -71,39 +135,34 @@ Shrine.storages = {
71
135
  Shrine.plugin :uppy_s3_multipart # load the plugin
72
136
  ```
73
137
 
74
- The plugin will provide a `Shrine.uppy_s3_multipart` method that creates a new
75
- `Uppy::S3Multipart::App` instance, which is a Rack app that you can mount
76
- inside your main application:
138
+ The plugin will provide a `Shrine.uppy_s3_multipart` method that creates the
139
+ `Uppy::S3Multipart::App` instance, which you can then mount inside your router:
77
140
 
78
141
  ```rb
79
- # Rails (config/routes.rb)
142
+ # config/routes.rb (Rails)
80
143
  Rails.application.routes.draw do
144
+ # ...
81
145
  mount Shrine.uppy_s3_multipart(:cache) => "/s3/multipart"
82
146
  end
83
-
84
- # Rack (config.ru)
85
- map "/s3/multipart" do
86
- run Shrine.uppy_s3_multipart(:cache)
87
- end
88
147
  ```
89
148
 
90
- Now in your Uppy configuration point `serverUrl` to your app's URL:
149
+ Now in your Uppy configuration point `companionUrl` to your app's URL:
91
150
 
92
151
  ```js
93
152
  // ...
94
153
  uppy.use(Uppy.AwsS3Multipart, {
95
- serverUrl: '/',
154
+ companionUrl: '/',
96
155
  })
97
156
  ```
98
157
 
99
- In the `upload-success` Uppy callback you can then construct the Shrine
100
- uploaded file data (this example assumes your temporary Shrine S3 storage has
101
- `prefix: "cache"` set):
158
+ In the `upload-success` Uppy callback, you can construct the Shrine uploaded
159
+ file data (this example assumes your temporary Shrine S3 storage has `prefix:
160
+ "cache"` set):
102
161
 
103
162
  ```js
104
- uppy.on('upload-success', function (file, data, uploadURL) {
163
+ uppy.on('upload-success', function (file, response) {
105
164
  var uploadedFileData = JSON.stringify({
106
- id: uploadURL.match(/\/cache\/([^\?]+)/)[1], // extract key without prefix
165
+ id: response.uploadURL.match(/\/cache\/([^\?]+)/)[1], // extract key without prefix
107
166
  storage: 'cache',
108
167
  metadata: {
109
168
  size: file.size,
@@ -115,108 +174,57 @@ uppy.on('upload-success', function (file, data, uploadURL) {
115
174
  })
116
175
  ```
117
176
 
118
- **See [Adding Direct S3 Uploads] for an example of a complete Uppy setup with
119
- Shrine. From there you can swap the `presign_endpoint` + `AwsS3` code with the
120
- `uppy_s3_multipart` + `AwsS3Multipart` setup.**
177
+ See [Adding Direct S3 Uploads] for an example of a complete Uppy setup with
178
+ Shrine. From there you can swap the `presign_endpoint` + `aws-s3` code with the
179
+ `uppy_s3_multipart` + `aws-s3-multipart` setup.
121
180
 
122
181
  Note that **Shrine won't extract metadata from directly upload files on
123
182
  assignment** by default. Instead, it will just copy metadata that was extracted
124
183
  on the client side. See [this section][metadata direct uploads] for the
125
184
  rationale and instructions on how to opt in.
126
185
 
127
- ### App
128
-
129
- You can also use `uppy-s3_multipart` without Shrine, by initializing the
130
- `Uppy::S3Multipart::App` directly:
131
-
132
- ```rb
133
- require "uppy/s3_multipart"
134
-
135
- resource = Aws::S3::Resource.new(
136
- access_key_id: "...",
137
- secret_access_key: "...",
138
- region: "...",
139
- )
140
-
141
- bucket = resource.bucket("my-bucket")
142
-
143
- UPPY_S3_MULTIPART_APP = Uppy::S3Multipart::App.new(bucket: bucket)
144
- ```
145
-
146
- You can mount it inside your main app in the same way:
147
-
148
- ```rb
149
- # Rails (config/routes.rb)
150
- Rails.application.routes.draw do
151
- mount UPPY_S3_MULTIPART_APP => "/s3/multipart"
152
- end
153
-
154
- # Rack (config.ru)
155
- map "/s3/multipart" do
156
- run UPPY_S3_MULTIPART_APP
157
- end
158
- ```
159
-
160
- This will add the routes that the `AwsS3Multipart` Uppy plugin expects:
161
-
162
- ```
163
- POST /s3/multipart
164
- GET /s3/multipart/:uploadId
165
- GET /s3/multipart/:uploadId/:partNumber
166
- POST /s3/multipart/:uploadId/complete
167
- DELETE /s3/multipart/:uploadId
168
- ```
169
-
170
- Now in your Uppy configuration point `serverUrl` to your app's URL:
171
-
172
- ```js
173
- // ...
174
- uppy.use(Uppy.AwsS3Multipart, {
175
- serverUrl: '/',
176
- })
177
- ```
178
-
179
- ### Configuration
186
+ ## Configuration
180
187
 
181
188
  This section describe various configuration options that you can pass to
182
189
  `Uppy::S3Multipart::App`.
183
190
 
184
191
  #### `:bucket`
185
192
 
186
- The `:bucket` option is mandatory and accepts an instance of `Aws::S3::Bucket`.
187
- It's easiest to create an `Aws::S3::Resource`, and call `#bucket` on it.
193
+ The `:bucket` option is mandatory and accepts an instance of `Aws::S3::Bucket`:
188
194
 
189
195
  ```rb
190
196
  require "uppy/s3_multipart"
191
197
 
192
- resource = Aws::S3::Resource.new(
198
+ bucket = Aws::S3::Bucket.new(
199
+ name: "<BUCKET>",
193
200
  access_key_id: "<ACCESS_KEY_ID>",
194
201
  secret_access_key: "<SECRET_ACCESS_KEY>",
195
202
  region: "<REGION>",
196
203
  )
197
204
 
198
- bucket = resource.bucket("<BUCKET>")
199
-
200
- Uppy::S3MUltipart::App.new(bucket: bucket)
205
+ Uppy::S3Multipart::App.new(bucket: bucket)
201
206
  ```
202
207
 
203
- If you want to use [Minio], you can easily configure your `Aws::S3::Bucket` to
204
- point to your Minio server:
208
+ If you want to use [Minio], you can easily configure the `Aws::S3::Bucket` to
209
+ use your Minio server:
205
210
 
206
211
  ```rb
207
- resource = Aws::S3::Resource.new(
212
+ bucket = Aws::S3::Bucket.new(
213
+ name: "<MINIO_BUCKET>",
208
214
  access_key_id: "<MINIO_ACCESS_KEY>", # "AccessKey" value
209
215
  secret_access_key: "<MINIO_SECRET_KEY>", # "SecretKey" value
210
216
  endpoint: "<MINIO_ENDPOINT>", # "Endpoint" value
211
217
  region: "us-east-1",
212
- force_path_style: true,
213
218
  )
214
219
 
215
- bucket = resource.bucket("<MINIO_BUCKET>") # name of the bucket you created
220
+ Uppy::S3Multipart::App.new(bucket: bucket)
216
221
  ```
217
222
 
218
- See the [`Aws::S3::Client#initialize`] docs for all supported configuration
219
- options. In the Shrine plugin this option is inferred from the S3 storage.
223
+ Except for `:name`, all options passed to [`Aws::S3::Bucket#initialize`] are
224
+ forwarded to [`Aws::S3::Client#initialize`], see its documentation for
225
+ additional options.
226
+
227
+ In the Shrine plugin this configuration is inferred from the S3 storage.
220
228
 
221
229
  #### `:prefix`
222
230
 
@@ -227,14 +235,7 @@ to be uploaded to.
227
235
  Uppy::S3Multipart::App.new(bucket: bucket, prefix: "cache")
228
236
  ```
229
237
 
230
- In the Shrine plugin this option is inferred from the S3 storage:
231
-
232
- ```rb
233
- Shrine.storages = {
234
- cache: Shrine::Storage::S3.new(prefix: "cache", **options),
235
- store: Shrine::Storage::S3.new(**options),
236
- }
237
- ```
238
+ In the Shrine plugin this option is inferred from the S3 storage.
238
239
 
239
240
  #### `:options`
240
241
 
@@ -326,7 +327,7 @@ Shrine.storages = {
326
327
  }
327
328
  ```
328
329
 
329
- ### Client
330
+ ## Client
330
331
 
331
332
  If you would rather implement the endpoints yourself, you can utilize the
332
333
  `Uppy::S3Multipart::Client` to make S3 requests.
@@ -475,13 +476,14 @@ Covenant](http://contributor-covenant.org) code of conduct.
475
476
  The gem is available as open source under the terms of the [MIT
476
477
  License](https://opensource.org/licenses/MIT).
477
478
 
478
- [AwsS3Multipart]: https://uppy.io/docs/aws-s3-multipart/
479
+ [aws-s3-multipart]: https://uppy.io/docs/aws-s3-multipart/
479
480
  [Shrine]: https://shrinerb.com
480
481
  [Adding Direct S3 Uploads]: https://github.com/shrinerb/shrine/wiki/Adding-Direct-S3-Uploads
481
482
  [Minio]: https://minio.io/
482
483
  [Client]: #client
483
484
  [content_disposition]: https://github.com/shrinerb/content_disposition
484
485
  [`Rack::Request`]: https://www.rubydoc.info/github/rack/rack/master/Rack/Request
486
+ [`Aws::S3::Bucket#initialize`]: https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Bucket.html#initialize-instance_method
485
487
  [`Aws::S3::Client#initialize`]: https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Client.html#initialize-instance_method
486
488
  [`Aws::S3::Client#create_multipart_upload`]: https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Client.html#create_multipart_upload-instance_method
487
489
  [`Aws::S3::Client#list_parts`]: https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Client.html#list_parts-instance_method
@@ -20,6 +20,11 @@ module Uppy
20
20
  @router.call(env)
21
21
  end
22
22
 
23
+ def inspect
24
+ "#<Uppy::S3Multipart::App>"
25
+ end
26
+ alias to_s inspect
27
+
23
28
  class Router < Roda
24
29
  plugin :all_verbs
25
30
  plugin :json
@@ -33,23 +38,27 @@ module Uppy
33
38
  route do |r|
34
39
  # POST /s3/multipart
35
40
  r.post ["", true] do
36
- content_type = r.params["type"]
37
- filename = r.params["filename"]
38
-
39
- extension = File.extname(filename.to_s)
40
- key = SecureRandom.hex + extension
41
- key = "#{opts[:prefix]}/#{key}" if opts[:prefix]
41
+ type = r.params["type"]
42
+ filename = r.params["filename"]
42
43
 
43
- content_disposition = ContentDisposition.inline(filename) if filename
44
+ key = SecureRandom.hex + File.extname(filename.to_s)
45
+ key = [*opts[:prefix], key].join("/")
44
46
 
45
- options = { content_type: content_type, content_disposition: content_disposition }
46
- options[:acl] = "public-read" if opts[:public]
47
+ options = {}
48
+ options[:content_type] = type if type
49
+ options[:content_disposition] = ContentDisposition.inline(filename) if filename
50
+ options[:acl] = "public-read" if opts[:public]
47
51
 
48
52
  result = client_call(:create_multipart_upload, key: key, **options)
49
53
 
50
54
  { uploadId: result.fetch(:upload_id), key: result.fetch(:key) }
51
55
  end
52
56
 
57
+ # OPTIONS /s3/multipart
58
+ r.options ["", true] do
59
+ r.halt 204
60
+ end
61
+
53
62
  # GET /s3/multipart/:uploadId
54
63
  r.get String do |upload_id|
55
64
  key = param!("key")
@@ -56,13 +56,7 @@ module Uppy
56
56
 
57
57
  def abort_multipart_upload(upload_id:, key:, **options)
58
58
  multipart_upload = multipart_upload(upload_id, key)
59
-
60
- # aws-sdk-s3 docs recommend retrying the abort in case the multipart
61
- # upload still has parts
62
- loop do
63
- multipart_upload.abort(**options)
64
- break unless multipart_upload.parts.any?
65
- end
59
+ multipart_upload.abort(**options)
66
60
 
67
61
  {}
68
62
  end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |gem|
2
2
  gem.name = "uppy-s3_multipart"
3
- gem.version = "0.3.1"
3
+ gem.version = "1.0.0"
4
4
 
5
5
  gem.required_ruby_version = ">= 2.2"
6
6
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uppy-s3_multipart
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Janko Marohnić
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-02-19 00:00:00.000000000 Z
11
+ date: 2021-07-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: roda
@@ -142,7 +142,7 @@ dependencies:
142
142
  - - "~>"
143
143
  - !ruby/object:Gem::Version
144
144
  version: '3.23'
145
- description:
145
+ description:
146
146
  email:
147
147
  - janko.marohnic@gmail.com
148
148
  executables: []
@@ -161,7 +161,7 @@ homepage: https://github.com/janko/uppy-s3_multipart
161
161
  licenses:
162
162
  - MIT
163
163
  metadata: {}
164
- post_install_message:
164
+ post_install_message:
165
165
  rdoc_options: []
166
166
  require_paths:
167
167
  - lib
@@ -176,8 +176,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
176
176
  - !ruby/object:Gem::Version
177
177
  version: '0'
178
178
  requirements: []
179
- rubygems_version: 3.0.1
180
- signing_key:
179
+ rubygems_version: 3.2.15
180
+ signing_key:
181
181
  specification_version: 4
182
182
  summary: Provides a Rack application that implements endpoints for the AwsS3Multipart
183
183
  Uppy plugin.