Add :public option for public uploads and URLs

parent 618f6793
......@@ -134,6 +134,14 @@ files**, instead it will just copy metadata that was extracted on the client
side. See [this section][metadata direct uploads] for the rationale and
instructions on how to opt in.
If you want to make uploads public and have public URLs without query
parameters returned, you can pass `public: true` to the Shrine storage (note
that this is supported starting from Shrine 2.13).
```rb
Shrine::Storage::S3.new(public: true, **options)
```
Both the plugin and method accept `:options` for specifying additional options
to the S3 client operations (see the [Client](#client) section for list of
operations and options they accept):
......@@ -194,9 +202,16 @@ uppy.use(Uppy.AwsS3Multipart, {
})
```
The `Uppy::S3Mutipart::App` initializer accepts `:options` for specifying
additional options to the S3 client operations (see the [Client](#client)
section for list of operations and options they accept):
If you want to make uploads public and have public URLs without query
parameters returned, you can pass `public: true` to the app.
```rb
Uppy::S3Multipart::App.new(bucket: bucket, public: true)
```
You can also pass `:options` for specifying additional options to the S3 client
operations (see the [Client](#client) section for list of operations and
options they accept):
```rb
Uppy::S3Multipart::App.new(bucket: bucket, options: {
......
......@@ -15,12 +15,12 @@ class Shrine
fail Error, "expected storage to be a Shrine::Storage::S3, but was #{s3.inspect}"
end
::Uppy::S3Multipart::App.new(
bucket: s3.bucket,
prefix: s3.prefix,
options: opts[:uppy_s3_multipart_options],
**options
)
options[:bucket] ||= s3.bucket
options[:prefix] ||= s3.prefix
options[:public] ||= s3.public if s3.respond_to?(:public)
options[:options] ||= opts[:uppy_s3_multipart_options]
::Uppy::S3Multipart::App.new(**options)
end
end
end
......
......@@ -8,10 +8,11 @@ require "cgi"
module Uppy
module S3Multipart
class App
def initialize(bucket:, prefix: nil, options: {})
def initialize(bucket:, prefix: nil, public: nil, options: {})
@router = Class.new(Router)
@router.opts[:client] = Client.new(bucket: bucket)
@router.opts[:prefix] = prefix
@router.opts[:public] = public
@router.opts[:options] = options
end
......@@ -42,7 +43,10 @@ module Uppy
# CGI-escape the filename because aws-sdk's signature calculator trips on special characters
content_disposition = "inline; filename=\"#{CGI.escape(filename)}\"" if filename
result = client_call(:create_multipart_upload, key: key, content_type: content_type, content_disposition: content_disposition)
options = { content_type: content_type, content_disposition: content_disposition }
options[:acl] = "public-read" if opts[:public]
result = client_call(:create_multipart_upload, key: key, **options)
{ uploadId: result.fetch(:upload_id), key: result.fetch(:key) }
end
......@@ -82,7 +86,7 @@ module Uppy
client_call(:complete_multipart_upload, upload_id: upload_id, key: key, parts: parts)
object_url = client_call(:object_url, key: key)
object_url = client_call(:object_url, key: key, public: opts[:public])
{ location: object_url }
end
......
......@@ -60,9 +60,21 @@ describe Uppy::S3Multipart::App do
response = app.post "/s3/multipart"
assert_equal :create_multipart_upload, @s3.api_requests[0][:operation_name]
assert_match /^prefix\/\w{32}/, @s3.api_requests[0][:params][:key]
assert_match /^prefix\/\w{32}$/, response.body_json["key"]
end
it "handles :public option" do
@endpoint = Uppy::S3Multipart::App.new(bucket: @bucket, public: true)
response = app.post "/s3/multipart"
assert_equal :create_multipart_upload, @s3.api_requests[0][:operation_name]
assert_equal "public-read", @s3.api_requests[0][:params][:acl]
end
it "handles :options as a hash" do
@endpoint = Uppy::S3Multipart::App.new(bucket: @bucket, options: {
create_multipart_upload: { acl: "public-read" }
......@@ -223,6 +235,19 @@ describe Uppy::S3Multipart::App do
assert_includes response.body_json["location"], "response-content-disposition"
end
it "handles :public option" do
@endpoint = Uppy::S3Multipart::App.new(bucket: @bucket, public: true)
response = app.post "/s3/multipart/foo/complete", query: { key: "bar" }, json: { parts: [] }
assert_equal 200, response.status
assert_equal "application/json", response.headers["Content-Type"]
uri = URI.parse(response.body_json["location"])
assert_nil uri.query
end
it "returns error response when 'key' parameter is missing" do
response = app.post "/s3/multipart/foo/complete", json: { parts: [] }
......
......@@ -53,6 +53,16 @@ describe Shrine::Plugins::UppyS3Multipart do
assert_match /^prefix\/\w+$/, client.api_requests[0][:params][:key]
end
it "passes the public" do
@shrine.storages[:s3] = s3(public: true)
app = test_app
app.post "/multipart"
assert_equal :create_multipart_upload, client.api_requests[0][:operation_name]
assert_match "public-read", client.api_requests[0][:params][:acl]
end
it "passes client options" do
@shrine.plugin :uppy_s3_multipart, options: {
create_multipart_upload: { acl: "public-read" },
......
......@@ -19,7 +19,7 @@ Gem::Specification.new do |gem|
gem.add_development_dependency "rake"
gem.add_development_dependency "minitest"
gem.add_development_dependency "rack-test_app"
gem.add_development_dependency "shrine", "~> 2.0"
gem.add_development_dependency "shrine", "~> 2.13"
gem.add_development_dependency "shrine-memory"
gem.add_development_dependency "aws-sdk-core", "~> 3.23"
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment