shrine 2.16.0 → 2.17.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.

Potentially problematic release.


This version of shrine might be problematic. Click here for more details.

@@ -18,7 +18,7 @@ class Shrine
18
18
  end
19
19
 
20
20
  module AttacherMethods
21
- def assign(value)
21
+ def assign(value, **options)
22
22
  super
23
23
  cached_file = get
24
24
 
@@ -17,8 +17,9 @@ class Shrine
17
17
 
18
18
  private
19
19
 
20
- def parsed_json?(hash)
21
- hash.keys.any? { |key| key.is_a?(String) }
20
+ def parsed_json?(value)
21
+ (value.key?('id') || value.key?(:id)) &&
22
+ (value.key?('storage') || value.key?(:storage))
22
23
  end
23
24
  end
24
25
  end
@@ -11,10 +11,8 @@ class Shrine
11
11
  # [doc/plugins/presign_endpoint.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/presign_endpoint.md
12
12
  module PresignEndpoint
13
13
  def self.configure(uploader, opts = {})
14
- uploader.opts[:presign_endpoint_presign_location] = opts.fetch(:presign_location, uploader.opts[:presign_endpoint_presign_location])
15
- uploader.opts[:presign_endpoint_presign_options] = opts.fetch(:presign_options, uploader.opts[:presign_endpoint_presign_options])
16
- uploader.opts[:presign_endpoint_presign] = opts.fetch(:presign, uploader.opts[:presign_endpoint_presign])
17
- uploader.opts[:presign_endpoint_rack_response] = opts.fetch(:rack_response, uploader.opts[:presign_endpoint_rack_response])
14
+ uploader.opts[:presign_endpoint] ||= {}
15
+ uploader.opts[:presign_endpoint].merge!(opts)
18
16
  end
19
17
 
20
18
  module ClassMethods
@@ -26,142 +24,148 @@ class Shrine
26
24
  # Additional options can be given to override the options given on
27
25
  # plugin initialization.
28
26
  def presign_endpoint(storage_key, **options)
29
- App.new(
30
- shrine_class: self,
31
- storage_key: storage_key,
32
- presign_location: opts[:presign_endpoint_presign_location],
33
- presign_options: opts[:presign_endpoint_presign_options],
34
- presign: opts[:presign_endpoint_presign],
35
- rack_response: opts[:presign_endpoint_rack_response],
36
- **options
27
+ Shrine::PresignEndpoint.new(
28
+ shrine_class: self,
29
+ storage_key: storage_key,
30
+ **opts[:presign_endpoint],
31
+ **options,
37
32
  )
38
33
  end
39
34
  end
35
+ end
40
36
 
41
- # Rack application that accepts GET request to the root URL, calls
42
- # `#presign` on the specified storage, and returns that information in
43
- # JSON format.
44
- class App
45
- CONTENT_TYPE_JSON = "application/json; charset=utf-8"
46
- CONTENT_TYPE_TEXT = "text/plain"
47
-
48
- # Writes given options to instance variables.
49
- def initialize(options)
50
- options.each do |name, value|
51
- instance_variable_set("@#{name}", value)
52
- end
53
- end
37
+ register_plugin(:presign_endpoint, PresignEndpoint)
38
+ end
54
39
 
55
- # Accepts a Rack env hash, routes GET requests to the root URL, and
56
- # returns a Rack response triple.
57
- #
58
- # If request isn't to the root URL, a `404 Not Found` response is
59
- # returned. If request verb isn't GET, a `405 Method Not Allowed`
60
- # response is returned.
61
- def call(env)
62
- request = Rack::Request.new(env)
40
+ # Rack application that accepts GET request to the root URL, calls
41
+ # `#presign` on the specified storage, and returns that information in
42
+ # JSON format.
43
+ class PresignEndpoint
44
+ CONTENT_TYPE_JSON = "application/json; charset=utf-8"
45
+ CONTENT_TYPE_TEXT = "text/plain"
46
+
47
+ # Writes given options to instance variables.
48
+ def initialize(options)
49
+ options.each do |name, value|
50
+ instance_variable_set("@#{name}", value)
51
+ end
52
+ end
63
53
 
64
- status, headers, body = catch(:halt) do
65
- error!(404, "Not Found") unless ["", "/"].include?(request.path_info)
66
- error!(405, "Method Not Allowed") unless request.get?
54
+ # Accepts a Rack env hash, routes GET requests to the root URL, and
55
+ # returns a Rack response triple.
56
+ #
57
+ # If request isn't to the root URL, a `404 Not Found` response is
58
+ # returned. If request verb isn't GET, a `405 Method Not Allowed`
59
+ # response is returned.
60
+ def call(env)
61
+ request = Rack::Request.new(env)
67
62
 
68
- handle_request(request)
69
- end
63
+ status, headers, body = catch(:halt) do
64
+ error!(404, "Not Found") unless ["", "/"].include?(request.path_info)
65
+ error!(405, "Method Not Allowed") unless request.get?
70
66
 
71
- headers["Content-Length"] = body.map(&:bytesize).inject(0, :+).to_s
67
+ handle_request(request)
68
+ end
72
69
 
73
- [status, headers, body]
74
- end
70
+ headers["Content-Length"] ||= body.map(&:bytesize).inject(0, :+).to_s
75
71
 
76
- private
72
+ [status, headers, body]
73
+ end
77
74
 
78
- # Accepts a `Rack::Request` object, generates the presign, and returns a
79
- # Rack response.
80
- def handle_request(request)
81
- location = get_presign_location(request)
82
- options = get_presign_options(request)
75
+ def inspect
76
+ "#<#{@shrine_class}::PresignEndpoint(:#{@storage_key})>"
77
+ end
78
+ alias to_s inspect
83
79
 
84
- presign = generate_presign(location, options, request)
80
+ private
85
81
 
86
- make_response(presign, request)
87
- end
82
+ # Accepts a `Rack::Request` object, generates the presign, and returns a
83
+ # Rack response.
84
+ def handle_request(request)
85
+ location = get_presign_location(request)
86
+ options = get_presign_options(request)
88
87
 
89
- # Generates the location using `Shrine#generate_uid`, and extracts the
90
- # extension from the `filename` query parameter. If `:presign_location`
91
- # option is given, calls that instead.
92
- def get_presign_location(request)
93
- if @presign_location
94
- @presign_location.call(request)
95
- else
96
- extension = File.extname(request.params["filename"].to_s)
97
- uploader.send(:generate_uid, nil) + extension
98
- end
99
- end
88
+ presign = generate_presign(location, options, request)
100
89
 
101
- # Calls `:presign_options` option block if given.
102
- def get_presign_options(request)
103
- options = @presign_options
104
- options = options.call(request) if options.respond_to?(:call)
105
- options || {}
106
- end
90
+ make_response(presign, request)
91
+ end
107
92
 
108
- # Calls `#presign` on the storage, and returns the `url`, `fields`, and
109
- # `headers` information in a serialializable format. If `:presign`
110
- # option is given, calls that instead of calling `#presign`.
111
- def generate_presign(location, options, request)
112
- if @presign
113
- data = @presign.call(location, options, request)
114
- else
115
- data = storage.presign(location, options)
116
- end
117
-
118
- if data.respond_to?(:to_h)
119
- { fields: {}, headers: {} }.merge(data.to_h)
120
- else
121
- Shrine.deprecation("Returning a custom object in Storage#presign is deprecated, presign_endpoint will not support it in Shrine 3. Storage#presign should return a Hash instead.")
122
-
123
- url = data.url
124
- fields = data.fields
125
- headers = data.headers if data.respond_to?(:headers)
126
-
127
- { url: url, fields: fields.to_h, headers: headers.to_h }
128
- end
129
- end
93
+ # Generates the location using `Shrine#generate_uid`, and extracts the
94
+ # extension from the `filename` query parameter. If `:presign_location`
95
+ # option is given, calls that instead.
96
+ def get_presign_location(request)
97
+ if @presign_location
98
+ @presign_location.call(request)
99
+ else
100
+ extension = File.extname(request.params["filename"].to_s)
101
+ uploader.send(:generate_uid, nil) + extension
102
+ end
103
+ end
130
104
 
131
- # Transforms the presign hash into a JSON response. It returns a Rack
132
- # response triple - an array consisting of a status number, hash of
133
- # headers, and a body enumerable. If `:rack_response` option is given,
134
- # calls that instead.
135
- def make_response(object, request)
136
- if @rack_response
137
- response = @rack_response.call(object, request)
138
- else
139
- response = [200, { "Content-Type" => CONTENT_TYPE_JSON }, [object.to_json]]
140
- end
141
-
142
- # prevent browsers from caching the response
143
- response[1]["Cache-Control"] = "no-store" unless response[1].key?("Cache-Control")
144
-
145
- response
146
- end
105
+ # Calls `:presign_options` option block if given.
106
+ def get_presign_options(request)
107
+ options = @presign_options
108
+ options = options.call(request) if options.respond_to?(:call)
109
+ options || {}
110
+ end
147
111
 
148
- # Used for early returning an error response.
149
- def error!(status, message)
150
- throw :halt, [status, { "Content-Type" => CONTENT_TYPE_TEXT }, [message]]
151
- end
112
+ # Calls `#presign` on the storage, and returns the `url`, `fields`, and
113
+ # `headers` information in a serialializable format. If `:presign`
114
+ # option is given, calls that instead of calling `#presign`.
115
+ def generate_presign(location, options, request)
116
+ if @presign
117
+ data = @presign.call(location, options, request)
118
+ else
119
+ data = storage.presign(location, options)
120
+ end
152
121
 
153
- # Returns the uploader around the specified storage.
154
- def uploader
155
- @shrine_class.new(@storage_key)
156
- end
122
+ if data.respond_to?(:to_h)
123
+ { fields: {}, headers: {} }.merge(data.to_h)
124
+ else
125
+ Shrine.deprecation("Returning a custom object in Storage#presign is deprecated, presign_endpoint will not support it in Shrine 3. Storage#presign should return a Hash instead.")
157
126
 
158
- # Returns the storage object.
159
- def storage
160
- @shrine_class.find_storage(@storage_key)
161
- end
127
+ url = data.url
128
+ fields = data.fields
129
+ headers = data.headers if data.respond_to?(:headers)
130
+
131
+ { url: url, fields: fields.to_h, headers: headers.to_h }
162
132
  end
163
133
  end
164
134
 
165
- register_plugin(:presign_endpoint, PresignEndpoint)
135
+ # Transforms the presign hash into a JSON response. It returns a Rack
136
+ # response triple - an array consisting of a status number, hash of
137
+ # headers, and a body enumerable. If `:rack_response` option is given,
138
+ # calls that instead.
139
+ def make_response(object, request)
140
+ if @rack_response
141
+ response = @rack_response.call(object, request)
142
+ else
143
+ response = [200, { "Content-Type" => CONTENT_TYPE_JSON }, [object.to_json]]
144
+ end
145
+
146
+ # prevent browsers from caching the response
147
+ response[1]["Cache-Control"] = "no-store" unless response[1].key?("Cache-Control")
148
+
149
+ response
150
+ end
151
+
152
+ # Used for early returning an error response.
153
+ def error!(status, message)
154
+ throw :halt, [status, { "Content-Type" => CONTENT_TYPE_TEXT }, [message]]
155
+ end
156
+
157
+ # Returns the uploader around the specified storage.
158
+ def uploader
159
+ @shrine_class.new(@storage_key)
160
+ end
161
+
162
+ # Returns the storage object.
163
+ def storage
164
+ @shrine_class.find_storage(@storage_key)
165
+ end
166
166
  end
167
+
168
+ # backwards compatibility
169
+ Plugins::PresignEndpoint.const_set(:App, PresignEndpoint)
170
+ Plugins::PresignEndpoint.deprecate_constant(:App)
167
171
  end
@@ -13,7 +13,7 @@ class Shrine
13
13
  module ClassMethods
14
14
  def process(action, &block)
15
15
  opts[:processing][action] ||= []
16
- opts[:processing][action] << block
16
+ opts[:processing][action] += [block]
17
17
  end
18
18
  end
19
19
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "rack"
4
4
  require "content_disposition"
5
+ require "digest"
5
6
 
6
7
  class Shrine
7
8
  module Plugins
@@ -49,18 +50,49 @@ class Shrine
49
50
  # metadata. Also returns the correct "Content-Range" header on ranged
50
51
  # requests.
51
52
  def rack_headers(filename: nil, type: nil, disposition: "inline", range: false)
52
- length = range ? range.size : file.size
53
- type ||= file.mime_type || Rack::Mime.mime_type(".#{file.extension}", nil)
53
+ {
54
+ "Content-Length" => content_length(range),
55
+ "Content-Type" => content_type(type),
56
+ "Content-Disposition" => content_disposition(disposition, filename),
57
+ "Content-Range" => content_range(range),
58
+ "Accept-Ranges" => accept_ranges(range),
59
+ "ETag" => etag,
60
+ }.compact
61
+ end
62
+
63
+ # Value for the "Content-Length" header.
64
+ def content_length(range)
65
+ length = range ? range.size : file.size
66
+ length.to_s if length
67
+ end
68
+
69
+ # Value for the "Content-Type" header.
70
+ def content_type(type)
71
+ type || file.mime_type || Rack::Mime.mime_type(".#{file.extension}", nil)
72
+ end
73
+
74
+ # Value for the "Content-Disposition" header.
75
+ def content_disposition(disposition, filename)
54
76
  filename ||= file.original_filename || file.id.split("/").last
55
77
 
56
- headers = {}
57
- headers["Content-Length"] = length.to_s if length
58
- headers["Content-Type"] = type if type
59
- headers["Content-Disposition"] = content_disposition(disposition, filename)
60
- headers["Content-Range"] = "bytes #{range.begin}-#{range.end}/#{file.size}" if range
61
- headers["Accept-Ranges"] = "bytes" unless range == false
78
+ ContentDisposition.format(disposition: disposition, filename: filename)
79
+ end
80
+
81
+ # Value for the "Content-Range" header.
82
+ def content_range(range)
83
+ "bytes #{range.begin}-#{range.end}/#{file.size}" if range
84
+ end
85
+
86
+ # Value for the "Accept-Ranges" header.
87
+ def accept_ranges(range)
88
+ "bytes" unless range == false
89
+ end
90
+
91
+ # Value for the "ETag" header.
92
+ def etag
93
+ digest = Digest::SHA256.hexdigest("#{file.shrine_class}-#{file.storage_key}-#{file.id}")
62
94
 
63
- headers
95
+ %(W/"#{digest.byteslice(0, 32)}")
64
96
  end
65
97
 
66
98
  # Returns an object that responds to #each and #close, which yields
@@ -79,10 +111,6 @@ class Shrine
79
111
 
80
112
  ranges.first if ranges && ranges.one?
81
113
  end
82
-
83
- def content_disposition(disposition, filename)
84
- ContentDisposition.format(disposition: disposition, filename: filename)
85
- end
86
114
  end
87
115
 
88
116
  # Implements the interface of a Rack response body object.
@@ -128,9 +156,12 @@ class Shrine
128
156
  read_chunks do |chunk|
129
157
  chunk_range = bytes_read..(bytes_read + chunk.bytesize - 1)
130
158
 
131
- if chunk_range.begin >= range.begin && chunk_range.end <= range.end
159
+ if chunk_range.begin > range.end
160
+ # no more chunks will match
161
+ return
162
+ elsif chunk_range.begin >= range.begin && chunk_range.end <= range.end
132
163
  yield chunk
133
- elsif chunk_range.end >= range.begin || chunk_range.end <= range.end
164
+ elsif chunk_range.end >= range.begin && chunk_range.begin <= range.end
134
165
  requested_range_begin = [chunk_range.begin, range.begin].max - bytes_read
135
166
  requested_range_end = [chunk_range.end, range.end].min - bytes_read
136
167
 
@@ -36,7 +36,7 @@ class Shrine
36
36
  # Downloads the remote file and assigns it. If download failed, sets
37
37
  # the error message and assigns the url to an instance variable so that
38
38
  # it shows up in the form.
39
- def assign_remote_url(url, downloader: {})
39
+ def assign_remote_url(url, downloader: {}, **options)
40
40
  return if url == "" || url.nil?
41
41
 
42
42
  begin
@@ -46,7 +46,7 @@ class Shrine
46
46
  end
47
47
 
48
48
  if downloaded_file
49
- assign(downloaded_file)
49
+ assign(downloaded_file, **options)
50
50
  else
51
51
  message = download_error_message(url, download_error)
52
52
  errors.replace [message]
@@ -16,10 +16,8 @@ class Shrine
16
16
  end
17
17
 
18
18
  def self.configure(uploader, opts = {})
19
- uploader.opts[:upload_endpoint_max_size] = opts.fetch(:max_size, uploader.opts[:upload_endpoint_max_size])
20
- uploader.opts[:upload_endpoint_upload_context] = opts.fetch(:upload_context, uploader.opts[:upload_endpoint_upload_context])
21
- uploader.opts[:upload_endpoint_upload] = opts.fetch(:upload, uploader.opts[:upload_endpoint_upload])
22
- uploader.opts[:upload_endpoint_rack_response] = opts.fetch(:rack_response, uploader.opts[:upload_endpoint_rack_response])
19
+ uploader.opts[:upload_endpoint] ||= {}
20
+ uploader.opts[:upload_endpoint].merge!(opts)
23
21
  end
24
22
 
25
23
  module ClassMethods
@@ -31,132 +29,138 @@ class Shrine
31
29
  # Additional options can be given to override the options given on
32
30
  # plugin initialization.
33
31
  def upload_endpoint(storage_key, **options)
34
- App.new(
35
- shrine_class: self,
36
- storage_key: storage_key,
37
- max_size: opts[:upload_endpoint_max_size],
38
- upload_context: opts[:upload_endpoint_upload_context],
39
- upload: opts[:upload_endpoint_upload],
40
- rack_response: opts[:upload_endpoint_rack_response],
41
- **options
32
+ Shrine::UploadEndpoint.new(
33
+ shrine_class: self,
34
+ storage_key: storage_key,
35
+ **opts[:upload_endpoint],
36
+ **options,
42
37
  )
43
38
  end
44
39
  end
40
+ end
45
41
 
46
- # Rack application that accepts multipart POST request to the root URL,
47
- # calls `#upload` with the uploaded file, and returns the uploaded file
48
- # information in JSON format.
49
- class App
50
- CONTENT_TYPE_JSON = "application/json; charset=utf-8"
51
- CONTENT_TYPE_TEXT = "text/plain"
52
-
53
- # Writes given options to instance variables.
54
- def initialize(options)
55
- options.each do |name, value|
56
- instance_variable_set("@#{name}", value)
57
- end
58
- end
42
+ register_plugin(:upload_endpoint, UploadEndpoint)
43
+ end
59
44
 
60
- # Accepts a Rack env hash, routes POST requests to the root URL, and
61
- # returns a Rack response triple.
62
- #
63
- # If request isn't to the root URL, a `404 Not Found` response is
64
- # returned. If request verb isn't GET, a `405 Method Not Allowed`
65
- # response is returned.
66
- def call(env)
67
- request = Rack::Request.new(env)
45
+ # Rack application that accepts multipart POST request to the root URL,
46
+ # calls `#upload` with the uploaded file, and returns the uploaded file
47
+ # information in JSON format.
48
+ class UploadEndpoint
49
+ CONTENT_TYPE_JSON = "application/json; charset=utf-8"
50
+ CONTENT_TYPE_TEXT = "text/plain"
51
+
52
+ # Writes given options to instance variables.
53
+ def initialize(options)
54
+ options.each do |name, value|
55
+ instance_variable_set("@#{name}", value)
56
+ end
57
+ end
68
58
 
69
- status, headers, body = catch(:halt) do
70
- error!(404, "Not Found") unless ["", "/"].include?(request.path_info)
71
- error!(405, "Method Not Allowed") unless request.post?
59
+ # Accepts a Rack env hash, routes POST requests to the root URL, and
60
+ # returns a Rack response triple.
61
+ #
62
+ # If request isn't to the root URL, a `404 Not Found` response is
63
+ # returned. If request verb isn't GET, a `405 Method Not Allowed`
64
+ # response is returned.
65
+ def call(env)
66
+ request = Rack::Request.new(env)
72
67
 
73
- handle_request(request)
74
- end
68
+ status, headers, body = catch(:halt) do
69
+ error!(404, "Not Found") unless ["", "/"].include?(request.path_info)
70
+ error!(405, "Method Not Allowed") unless request.post?
75
71
 
76
- headers["Content-Length"] = body.map(&:bytesize).inject(0, :+).to_s
72
+ handle_request(request)
73
+ end
77
74
 
78
- [status, headers, body]
79
- end
75
+ headers["Content-Length"] ||= body.map(&:bytesize).inject(0, :+).to_s
80
76
 
81
- private
77
+ [status, headers, body]
78
+ end
82
79
 
83
- # Accepts a `Rack::Request` object, uploads the file, and returns a Rack
84
- # response.
85
- def handle_request(request)
86
- io = get_io(request)
87
- context = get_context(request)
80
+ def inspect
81
+ "#<#{@shrine_class}::UploadEndpoint(:#{@storage_key})>"
82
+ end
83
+ alias to_s inspect
88
84
 
89
- uploaded_file = upload(io, context, request)
85
+ private
90
86
 
91
- make_response(uploaded_file, request)
92
- end
87
+ # Accepts a `Rack::Request` object, uploads the file, and returns a Rack
88
+ # response.
89
+ def handle_request(request)
90
+ io = get_io(request)
91
+ context = get_context(request)
93
92
 
94
- # Retrieves the "file" multipart request parameter, and returns an
95
- # IO-like object that can be passed to `Shrine#upload`.
96
- def get_io(request)
97
- file = request.params["file"]
93
+ uploaded_file = upload(io, context, request)
98
94
 
99
- error!(400, "Upload Not Found") if file.nil?
100
- error!(400, "Upload Not Valid") unless file.is_a?(Hash) && file[:tempfile]
101
- error!(413, "Upload Too Large") if @max_size && file[:tempfile].size > @max_size
95
+ make_response(uploaded_file, request)
96
+ end
102
97
 
103
- verify_checksum!(file[:tempfile], request.env["HTTP_CONTENT_MD5"]) if request.env["HTTP_CONTENT_MD5"]
98
+ # Retrieves the "file" multipart request parameter, and returns an
99
+ # IO-like object that can be passed to `Shrine#upload`.
100
+ def get_io(request)
101
+ file = request.params["file"]
104
102
 
105
- @shrine_class.rack_file(file)
106
- end
103
+ error!(400, "Upload Not Found") if file.nil?
104
+ error!(400, "Upload Not Valid") unless file.is_a?(Hash) && file[:tempfile]
105
+ error!(413, "Upload Too Large") if @max_size && file[:tempfile].size > @max_size
107
106
 
108
- # Returns a hash of information containing `:action` and `:request`
109
- # keys, which is to be passed to `Shrine#upload`. Calls
110
- # `:upload_context` option if given.
111
- def get_context(request)
112
- context = { action: :upload, phase: :upload, request: request }
113
- context.merge! @upload_context.call(request) if @upload_context
114
- context
115
- end
107
+ verify_checksum!(file[:tempfile], request.env["HTTP_CONTENT_MD5"]) if request.env["HTTP_CONTENT_MD5"]
116
108
 
117
- # Calls `Shrine#upload` with the given IO and context, and returns a
118
- # `Shrine::UploadedFile` object. If `:upload` option is given, calls
119
- # that instead.
120
- def upload(io, context, request)
121
- if @upload
122
- @upload.call(io, context, request)
123
- else
124
- uploader.upload(io, context)
125
- end
126
- end
109
+ @shrine_class.rack_file(file)
110
+ end
127
111
 
128
- # Transforms the uploaded file object into a JSON response. It returns
129
- # a Rack response triple - an array consisting of a status number, hash
130
- # of headers, and a body enumerable. If a `:rack_response` option is
131
- # given, calls that instead.
132
- def make_response(object, request)
133
- if @rack_response
134
- @rack_response.call(object, request)
135
- else
136
- [200, { "Content-Type" => CONTENT_TYPE_JSON }, [object.to_json]]
137
- end
138
- end
112
+ # Returns a hash of information containing `:action` and `:request`
113
+ # keys, which is to be passed to `Shrine#upload`. Calls
114
+ # `:upload_context` option if given.
115
+ def get_context(request)
116
+ context = { action: :upload, phase: :upload, request: request }
117
+ context.merge! @upload_context.call(request) if @upload_context
118
+ context
119
+ end
139
120
 
140
- # Verifies the provided checksum against the received file.
141
- def verify_checksum!(file, provided_checksum)
142
- error!(400, "The Content-MD5 you specified was invalid") if provided_checksum.length != 24
121
+ # Calls `Shrine#upload` with the given IO and context, and returns a
122
+ # `Shrine::UploadedFile` object. If `:upload` option is given, calls
123
+ # that instead.
124
+ def upload(io, context, request)
125
+ if @upload
126
+ @upload.call(io, context, request)
127
+ else
128
+ uploader.upload(io, context)
129
+ end
130
+ end
143
131
 
144
- calculated_checksum = Digest::MD5.file(file.path).base64digest
145
- error!(460, "The Content-MD5 you specified did not match what was recieved") if provided_checksum != calculated_checksum
146
- end
132
+ # Transforms the uploaded file object into a JSON response. It returns
133
+ # a Rack response triple - an array consisting of a status number, hash
134
+ # of headers, and a body enumerable. If a `:rack_response` option is
135
+ # given, calls that instead.
136
+ def make_response(object, request)
137
+ if @rack_response
138
+ @rack_response.call(object, request)
139
+ else
140
+ [200, { "Content-Type" => CONTENT_TYPE_JSON }, [object.to_json]]
141
+ end
142
+ end
147
143
 
148
- # Used for early returning an error response.
149
- def error!(status, message)
150
- throw :halt, [status, { "Content-Type" => CONTENT_TYPE_TEXT }, [message]]
151
- end
144
+ # Verifies the provided checksum against the received file.
145
+ def verify_checksum!(file, provided_checksum)
146
+ error!(400, "The Content-MD5 you specified was invalid") if provided_checksum.length != 24
152
147
 
153
- # Returns the uploader around the specified storage.
154
- def uploader
155
- @shrine_class.new(@storage_key)
156
- end
157
- end
148
+ calculated_checksum = Digest::MD5.file(file.path).base64digest
149
+ error!(460, "The Content-MD5 you specified did not match what was recieved") if provided_checksum != calculated_checksum
158
150
  end
159
151
 
160
- register_plugin(:upload_endpoint, UploadEndpoint)
152
+ # Used for early returning an error response.
153
+ def error!(status, message)
154
+ throw :halt, [status, { "Content-Type" => CONTENT_TYPE_TEXT }, [message]]
155
+ end
156
+
157
+ # Returns the uploader around the specified storage.
158
+ def uploader
159
+ @shrine_class.new(@storage_key)
160
+ end
161
161
  end
162
+
163
+ # backwards compatibility
164
+ Plugins::UploadEndpoint.const_set(:App, UploadEndpoint)
165
+ Plugins::UploadEndpoint.deprecate_constant(:App)
162
166
  end