refile 0.3.0 → 0.4.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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +56 -0
  3. data/.travis.yml +11 -0
  4. data/Gemfile +1 -1
  5. data/History.md +15 -0
  6. data/README.md +41 -5
  7. data/Rakefile +4 -1
  8. data/config/locales/en.yml +2 -0
  9. data/config/routes.rb +4 -2
  10. data/lib/refile/app.rb +96 -71
  11. data/lib/refile/attacher.rb +115 -0
  12. data/lib/refile/attachment/active_record.rb +5 -5
  13. data/lib/refile/attachment.rb +50 -117
  14. data/lib/refile/backend/file_system.rb +3 -3
  15. data/lib/refile/backend/s3.rb +7 -12
  16. data/lib/refile/file.rb +1 -3
  17. data/lib/refile/image_processing.rb +6 -3
  18. data/lib/refile/rails/attachment_helper.rb +18 -21
  19. data/lib/refile/rails.rb +2 -1
  20. data/lib/refile/random_hasher.rb +9 -8
  21. data/lib/refile/signature.rb +16 -0
  22. data/lib/refile/version.rb +1 -1
  23. data/lib/refile.rb +59 -1
  24. data/refile.gemspec +10 -6
  25. data/spec/refile/app_spec.rb +28 -4
  26. data/spec/refile/attachment_spec.rb +134 -33
  27. data/spec/refile/backend_examples.rb +7 -11
  28. data/spec/refile/features/direct_upload_spec.rb +0 -1
  29. data/spec/refile/features/normal_upload_spec.rb +21 -0
  30. data/spec/refile/features/presigned_upload_spec.rb +0 -1
  31. data/spec/refile/rails/attachment_helper_spec.rb +61 -0
  32. data/spec/refile/spec_helper.rb +26 -20
  33. data/spec/refile/test_app/app/controllers/normal_posts_controller.rb +10 -1
  34. data/spec/refile/test_app/app/controllers/presigned_posts_controller.rb +1 -0
  35. data/spec/refile/test_app/app/models/post.rb +1 -1
  36. data/spec/refile/test_app/app/views/normal_posts/index.html +5 -0
  37. data/spec/refile/test_app/app/views/normal_posts/show.html.erb +2 -0
  38. data/spec/refile/test_app/config/routes.rb +1 -1
  39. data/spec/refile/test_app.rb +13 -6
  40. data/spec/refile_spec.rb +39 -0
  41. metadata +51 -2
@@ -1,89 +1,5 @@
1
1
  module Refile
2
2
  module Attachment
3
- # @api private
4
- class Attachment
5
- attr_reader :record, :name, :cache, :store, :cache_id, :options, :errors
6
- attr_accessor :remove
7
-
8
- def initialize(record, name, **options)
9
- @record = record
10
- @name = name
11
- @options = options
12
- @cache = Refile.backends.fetch(@options[:cache].to_s)
13
- @store = Refile.backends.fetch(@options[:store].to_s)
14
- @errors = []
15
- end
16
-
17
- def id
18
- record.send(:"#{name}_id")
19
- end
20
-
21
- def id=(id)
22
- record.send(:"#{name}_id=", id)
23
- end
24
-
25
- def file
26
- if cached?
27
- cache.get(cache_id)
28
- elsif id and not id == ""
29
- store.get(id)
30
- end
31
- end
32
-
33
- def file=(uploadable)
34
- @cache_file = cache.upload(uploadable)
35
- @cache_id = @cache_file.id
36
- @errors = []
37
- rescue Refile::Invalid
38
- @errors = [:too_large]
39
- raise if @options[:raise_errors]
40
- end
41
-
42
- def download(url)
43
- if url and not url == ""
44
- raw_response = RestClient::Request.new(method: :get, url: url, raw_response: true).execute
45
- self.file = raw_response.file
46
- end
47
- rescue RestClient::Exception
48
- @errors = [:download_failed]
49
- raise if @options[:raise_errors]
50
- end
51
-
52
- def cache_id=(id)
53
- @cache_id = id unless @cache_file
54
- end
55
-
56
- def store!
57
- if remove?
58
- delete!
59
- elsif cached?
60
- file = store.upload(cache.get(cache_id))
61
- delete!
62
- self.id = file.id
63
- end
64
- end
65
-
66
- def delete!
67
- if cached?
68
- cache.delete(cache_id)
69
- @cache_id = nil
70
- @cache_file = nil
71
- end
72
- store.delete(id) if id
73
- self.id = nil
74
- end
75
-
76
- def remove?
77
- remove and remove != "" and remove !~ /\A0|false$\z/
78
- end
79
-
80
- private
81
-
82
- def cached?
83
- cache_id and not cache_id == ""
84
- end
85
- end
86
-
87
3
  # Macro which generates accessors for the given column which make it
88
4
  # possible to upload and retrieve previously uploaded files through the
89
5
  # generated accessors.
@@ -92,50 +8,67 @@ module Refile
92
8
  # should immediately raise an error, or save the error and defer handling
93
9
  # it until later.
94
10
  #
95
- # @param [String] name Name of the column which accessor are generated for
96
- # @param [#to_s] cache Name of a backend in +Refile.backends+ to use as transient cache
97
- # @param [#to_s] store Name of a backend in +Refile.backends+ to use as permanent store
98
- # @param [true, false] raise_errors Whether to raise errors in case an invalid file is assigned
99
- def attachment(name, cache: :cache, store: :store, raise_errors: true)
100
- attachment = :"#{name}_attachment"
11
+ # @param [String] name Name of the column which accessor are generated for
12
+ # @param [#to_s] cache Name of a backend in +Refile.backends+ to use as transient cache
13
+ # @param [#to_s] store Name of a backend in +Refile.backends+ to use as permanent store
14
+ # @param [true, false] raise_errors Whether to raise errors in case an invalid file is assigned
15
+ # @param [:image, nil] type The type of file that can be uploaded, currently +:image+ is the
16
+ # only valid value and restricts uploads to JPEG, PNG and GIF images
17
+ # @param [String, Array<String>, nil] extension Limit the uploaded file to the given extension or list of extensions
18
+ # @param [String, Array<String>, nil] content_type Limit the uploaded file to the given content type or list of content types
19
+ # @ignore
20
+ # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
21
+ def attachment(name, cache: :cache, store: :store, raise_errors: true, type: nil, extension: nil, content_type: nil)
22
+ mod = Module.new do
23
+ attacher = :"#{name}_attacher"
24
+
25
+ define_method attacher do
26
+ ivar = :"@#{attacher}"
27
+ instance_variable_get(ivar) or begin
28
+ instance_variable_set(ivar, Attacher.new(self, name,
29
+ cache: cache,
30
+ store: store,
31
+ raise_errors: raise_errors,
32
+ type: type,
33
+ extension: extension,
34
+ content_type: content_type
35
+ ))
36
+ end
37
+ end
101
38
 
102
- define_method attachment do
103
- ivar = :"@#{attachment}"
104
- instance_variable_get(ivar) or begin
105
- instance_variable_set(ivar, Attachment.new(self, name, cache: cache, store: store, raise_errors: raise_errors))
39
+ define_method "#{name}=" do |uploadable|
40
+ send(attacher).cache!(uploadable)
106
41
  end
107
- end
108
42
 
109
- define_method "#{name}=" do |uploadable|
110
- send(attachment).file = uploadable
111
- end
43
+ define_method name do
44
+ send(attacher).get
45
+ end
112
46
 
113
- define_method name do
114
- send(attachment).file
115
- end
47
+ define_method "#{name}_cache_id=" do |cache_id|
48
+ send(attacher).cache_id = cache_id
49
+ end
116
50
 
117
- define_method "#{name}_cache_id=" do |cache_id|
118
- send(attachment).cache_id = cache_id
119
- end
51
+ define_method "#{name}_cache_id" do
52
+ send(attacher).cache_id
53
+ end
120
54
 
121
- define_method "#{name}_cache_id" do
122
- send(attachment).cache_id
123
- end
55
+ define_method "remove_#{name}=" do |remove|
56
+ send(attacher).remove = remove
57
+ end
124
58
 
125
- define_method "remove_#{name}=" do |remove|
126
- send(attachment).remove = remove
127
- end
59
+ define_method "remove_#{name}" do
60
+ send(attacher).remove
61
+ end
128
62
 
129
- define_method "remove_#{name}" do
130
- send(attachment).remove
131
- end
63
+ define_method "remote_#{name}_url=" do |url|
64
+ send(attacher).download(url)
65
+ end
132
66
 
133
- define_method "remote_#{name}_url=" do |url|
134
- send(attachment).download(url)
67
+ define_method "remote_#{name}_url" do
68
+ end
135
69
  end
136
70
 
137
- define_method "remote_#{name}_url" do
138
- end
71
+ include mod
139
72
  end
140
73
  end
141
74
  end
@@ -1,7 +1,7 @@
1
1
  module Refile
2
2
  module Backend
3
3
  class FileSystem
4
- attr_reader :directory
4
+ attr_reader :directory, :max_size
5
5
 
6
6
  def initialize(directory, max_size: nil, hasher: Refile::RandomHasher.new)
7
7
  @hasher = hasher
@@ -53,11 +53,11 @@ module Refile
53
53
  end
54
54
 
55
55
  def exists?(id)
56
- ::File.exists?(path(id))
56
+ ::File.exist?(path(id))
57
57
  end
58
58
 
59
59
  def clear!(confirm = nil)
60
- raise ArgumentError, "are you sure? this will remove all files in the backend, call as `clear!(:confirm)` if you're sure you want to do this" unless confirm == :confirm
60
+ raise Refile::Confirm unless confirm == :confirm
61
61
  FileUtils.rm_rf(@directory)
62
62
  FileUtils.mkdir_p(@directory)
63
63
  end
@@ -2,10 +2,8 @@ require "aws-sdk"
2
2
 
3
3
  module Refile
4
4
  module Backend
5
-
6
5
  # A refile backend which stores files in Amazon S3
7
6
  class S3
8
-
9
7
  # Emulates an IO-object like interface on top of S3Object#read. To avoid
10
8
  # memory allocations and unnecessary complexity, this treats the `length`
11
9
  # parameter to read as a boolean flag instead. If given, it will read the
@@ -21,9 +19,7 @@ module Refile
21
19
  result = if length
22
20
  raise "closed" if @closed
23
21
 
24
- unless eof? # sets @peek
25
- @peek
26
- end
22
+ @peek unless eof? # sets @peek
27
23
  else
28
24
  @object.read
29
25
  end
@@ -55,14 +51,13 @@ module Refile
55
51
  end
56
52
  end
57
53
 
58
- Signature = Struct.new(:as, :id, :url, :fields)
59
-
60
- attr_reader :access_key_id
54
+ attr_reader :access_key_id, :max_size
61
55
 
62
- def initialize(access_key_id:, secret_access_key:, bucket:, max_size: nil, prefix: nil, hasher: Refile::RandomHasher.new)
56
+ def initialize(access_key_id:, secret_access_key:, bucket:, max_size: nil, prefix: nil, hasher: Refile::RandomHasher.new, **s3_options)
63
57
  @access_key_id = access_key_id
64
58
  @secret_access_key = secret_access_key
65
- @s3 = AWS::S3.new(access_key_id: access_key_id, secret_access_key: secret_access_key)
59
+ @s3_options = { access_key_id: access_key_id, secret_access_key: secret_access_key }.merge s3_options
60
+ @s3 = AWS::S3.new @s3_options
66
61
  @bucket_name = bucket
67
62
  @bucket = @s3.buckets[@bucket_name]
68
63
  @hasher = hasher
@@ -113,7 +108,7 @@ module Refile
113
108
  end
114
109
 
115
110
  def clear!(confirm = nil)
116
- raise ArgumentError, "are you sure? this will remove all files in the backend, call as `clear!(:confirm)` if you're sure you want to do this" unless confirm == :confirm
111
+ raise Refile::Confirm unless confirm == :confirm
117
112
  @bucket.objects.with_prefix(@prefix).delete_all
118
113
  end
119
114
 
@@ -121,7 +116,7 @@ module Refile
121
116
  id = RandomHasher.new.hash
122
117
  signature = @bucket.presigned_post(key: [*@prefix, id].join("/"))
123
118
  signature.where(content_length: @max_size) if @max_size
124
- Signature.new("file", id, signature.url.to_s, signature.fields)
119
+ Signature.new(as: "file", id: id, url: signature.url.to_s, fields: signature.fields)
125
120
  end
126
121
 
127
122
  def object(id)
data/lib/refile/file.rb CHANGED
@@ -48,9 +48,7 @@ module Refile
48
48
 
49
49
  def each
50
50
  if block_given?
51
- until eof?
52
- yield(read(Refile.read_chunk_size))
53
- end
51
+ yield(read(Refile.read_chunk_size)) until eof?
54
52
  else
55
53
  to_enum
56
54
  end
@@ -19,14 +19,17 @@ module Refile
19
19
  img.resize "#{width}x#{height}"
20
20
  end
21
21
 
22
- def fill(img, width, height, gravity = 'Center')
22
+ # @ignore
23
+ # rubocop:disable Metrics/AbcSize
24
+ # FIXME: test and rewrite to simpler implementation!
25
+ def fill(img, width, height, gravity = "Center")
23
26
  width = width.to_i
24
27
  height = height.to_i
25
28
  cols, rows = img[:dimensions]
26
29
  img.combine_options do |cmd|
27
30
  if width != cols || height != rows
28
- scale_x = width/cols.to_f
29
- scale_y = height/rows.to_f
31
+ scale_x = width / cols.to_f
32
+ scale_y = height / rows.to_f
30
33
  if scale_x >= scale_y
31
34
  cols = (scale_x * (cols + 0.5)).round
32
35
  rows = (scale_x * (rows + 0.5)).round
@@ -1,58 +1,55 @@
1
1
  module Refile
2
2
  module AttachmentHelper
3
- def attachment_url(record, name, *args, filename: nil, format: nil)
3
+ def attachment_url(record, name, *args, filename: nil, format: nil, host: nil)
4
4
  file = record.send(name)
5
5
  return unless file
6
6
 
7
7
  filename ||= name.to_s
8
8
 
9
9
  backend_name = Refile.backends.key(file.backend)
10
- host = Refile.host || request.base_url
10
+ host = host || Refile.host || request.base_url
11
11
 
12
12
  filename = filename.parameterize("_")
13
13
  filename << "." << format.to_s if format
14
14
 
15
- ::File.join(host, main_app.refile_app_path, backend_name, *args.map(&:to_s), file.id, filename)
15
+ ::File.join(host, main_app.refile_app_path, backend_name, *args.map(&:to_s), file.id.to_s, filename)
16
16
  end
17
17
 
18
- def attachment_image_tag(record, name, *args, fallback: nil, format: nil, **options)
18
+ def attachment_image_tag(record, name, *args, fallback: nil, format: nil, host: nil, **options)
19
19
  file = record.send(name)
20
20
  classes = ["attachment", record.class.model_name.singular, name, *options[:class]]
21
21
 
22
22
  if file
23
- image_tag(attachment_url(record, name, *args, format: format), options.merge(class: classes))
23
+ image_tag(attachment_url(record, name, *args, format: format, host: host), options.merge(class: classes))
24
24
  elsif fallback
25
25
  classes << "fallback"
26
26
  image_tag(fallback, options.merge(class: classes))
27
27
  end
28
28
  end
29
29
 
30
+ # @ignore
31
+ # rubocop:disable Metrics/AbcSize
30
32
  def attachment_field(object_name, method, options = {})
33
+ options[:data] ||= {}
34
+
31
35
  if options[:object]
32
- cache = options[:object].send(:"#{method}_attachment").cache
36
+ attacher = options[:object].send(:"#{method}_attacher")
37
+ options[:accept] = attacher.accept
33
38
 
34
39
  if options[:direct]
35
- host = Refile.host || request.base_url
36
- backend_name = Refile.backends.key(cache)
40
+ host = options[:host] || Refile.host || request.base_url
41
+ backend_name = Refile.backends.key(attacher.cache)
37
42
 
38
- options[:data] ||= {}
39
- options[:data][:direct] = true
40
- options[:data][:as] = "file"
41
- options[:data][:url] = ::File.join(host, main_app.refile_app_path, backend_name)
43
+ url = ::File.join(host, main_app.refile_app_path, backend_name)
44
+ options[:data].merge!(direct: true, as: "file", url: url)
42
45
  end
43
46
 
44
- if options[:presigned] and cache.respond_to?(:presign)
45
- signature = cache.presign
46
- options[:data] ||= {}
47
- options[:data][:direct] = true
48
- options[:data][:id] = signature.id
49
- options[:data][:url] = signature.url
50
- options[:data][:fields] = signature.fields
51
- options[:data][:as] = signature.as
47
+ if options[:presigned] and attacher.cache.respond_to?(:presign)
48
+ options[:data].merge!(direct: true).merge!(attacher.cache.presign.as_json)
52
49
  end
53
50
  end
54
51
  hidden_field(object_name, :"#{method}_cache_id", options.slice(:object)) +
55
- file_field(object_name, method, options)
52
+ file_field(object_name, method, options)
56
53
  end
57
54
  end
58
55
  end
data/lib/refile/rails.rb CHANGED
@@ -23,7 +23,8 @@ module Refile
23
23
  end
24
24
 
25
25
  initializer "refile.app" do
26
- Refile.app = Refile::App.new(logger: Rails.logger)
26
+ Refile.logger = Rails.logger
27
+ Refile.app = Refile::App.new
27
28
  end
28
29
  end
29
30
  end
@@ -1,10 +1,11 @@
1
- # A file hasher which ignores the file contents and always returns a random string.
2
- class Refile::RandomHasher
3
-
4
- # Generate a random string
5
- #
6
- # @return [String]
7
- def hash(uploadable=nil)
8
- SecureRandom.hex(30)
1
+ module Refile
2
+ # A file hasher which ignores the file contents and always returns a random string.
3
+ class RandomHasher
4
+ # Generate a random string
5
+ #
6
+ # @return [String]
7
+ def hash(_uploadable = nil)
8
+ SecureRandom.hex(30)
9
+ end
9
10
  end
10
11
  end
@@ -0,0 +1,16 @@
1
+ module Refile
2
+ class Signature
3
+ attr_reader :as, :id, :url, :fields
4
+
5
+ def initialize(as:, id:, url:, fields:)
6
+ @as = as
7
+ @id = id
8
+ @url = url
9
+ @fields = fields
10
+ end
11
+
12
+ def as_json(*)
13
+ { as: @as, id: @id, url: @url, fields: @fields }
14
+ end
15
+ end
16
+ end
@@ -1,3 +1,3 @@
1
1
  module Refile
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.0"
3
3
  end
data/lib/refile.rb CHANGED
@@ -2,12 +2,20 @@ require "uri"
2
2
  require "fileutils"
3
3
  require "tempfile"
4
4
  require "rest_client"
5
+ require "logger"
6
+ require "mime/types"
5
7
 
6
8
  module Refile
7
9
  class Invalid < StandardError; end
10
+ class Confirm < StandardError
11
+ def message
12
+ "are you sure? this will remove all files in the backend, call as \
13
+ `clear!(:confirm)` if you're sure you want to do this"
14
+ end
15
+ end
16
+ ONE_YEAR_IN_SECONDS = 31_557_600
8
17
 
9
18
  class << self
10
-
11
19
  # The number of bytes to read when files are streamed. Refile
12
20
  # uses this in a couple of places where files should be streamed
13
21
  # in a memory efficient way instead of reading the entire file into
@@ -40,6 +48,29 @@ module Refile
40
48
  # @return [Array[String]]
41
49
  attr_accessor :direct_upload
42
50
 
51
+ # Logger that should be used by rack application
52
+ #
53
+ # @return [Logger]
54
+ attr_accessor :logger
55
+
56
+ # Value for Access-Control-Allow-Origin header
57
+ #
58
+ # @return [String]
59
+ attr_accessor :allow_origin
60
+
61
+ # Value for Cache-Control: max-age=<value in seconds> header
62
+ attr_accessor :content_max_age
63
+
64
+ # Where should the rack application be mounted?
65
+ # The default is 'attachments'
66
+ attr_accessor :mount_point
67
+
68
+ # Should the rack application be automounted in a Rails app?
69
+ # The default is true.
70
+ # If set to false then Refile.app should be mounted in the Rails application
71
+ # routes.rb with the options `at: Refile.mount_point, as: :refile_app`
72
+ attr_accessor :automount
73
+
43
74
  # A global registry of backends.
44
75
  #
45
76
  # @return [Hash{String => Backend}]
@@ -146,9 +177,31 @@ module Refile
146
177
  end
147
178
  true
148
179
  end
180
+
181
+ def extract_filename(uploadable)
182
+ path = if uploadable.respond_to?(:original_filename)
183
+ uploadable.original_filename
184
+ elsif uploadable.respond_to?(:path)
185
+ uploadable.path
186
+ end
187
+ ::File.basename(path) if path
188
+ end
189
+
190
+ def extract_content_type(uploadable)
191
+ if uploadable.respond_to?(:content_type)
192
+ uploadable.content_type
193
+ else
194
+ filename = extract_filename(uploadable)
195
+ if filename
196
+ content_type = MIME::Types.of(filename).first
197
+ content_type.to_s if content_type
198
+ end
199
+ end
200
+ end
149
201
  end
150
202
 
151
203
  require "refile/version"
204
+ require "refile/attacher"
152
205
  require "refile/attachment"
153
206
  require "refile/random_hasher"
154
207
  require "refile/file"
@@ -162,4 +215,9 @@ Refile.configure do |config|
162
215
  # one?
163
216
  config.read_chunk_size = 3000
164
217
  config.direct_upload = ["cache"]
218
+ config.allow_origin = "*"
219
+ config.logger = Logger.new(STDOUT)
220
+ config.mount_point = "attachments"
221
+ config.automount = true
222
+ config.content_max_age = Refile::ONE_YEAR_IN_SECONDS
165
223
  end
data/refile.gemspec CHANGED
@@ -1,24 +1,27 @@
1
1
  # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
2
+ lib = File.expand_path("../lib", __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'refile/version'
4
+ require "refile/version"
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "refile"
8
8
  spec.version = Refile::VERSION
9
9
  spec.authors = ["Jonas Nicklas"]
10
10
  spec.email = ["jonas.nicklas@gmail.com"]
11
- spec.summary = %q{Simple and powerful file upload library}
11
+ spec.summary = "Simple and powerful file upload library"
12
12
  spec.homepage = ""
13
13
  spec.license = "MIT"
14
14
 
15
15
  spec.files = `git ls-files -z`.split("\x0")
16
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
- spec.require_paths = ["lib", "spec"]
16
+ spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(/^(test|spec|features)\//)
18
+ spec.require_paths = %w[lib spec]
19
19
 
20
20
  spec.required_ruby_version = ">= 2.1.0"
21
+
21
22
  spec.add_dependency "rest-client", "~> 1.7.2"
23
+ spec.add_dependency "sinatra", "~> 1.4.5"
24
+ spec.add_dependency "mime-types"
22
25
 
23
26
  spec.add_development_dependency "webmock", "~> 1.20.4"
24
27
  spec.add_development_dependency "bundler", "~> 1.6"
@@ -34,4 +37,5 @@ Gem::Specification.new do |spec|
34
37
  spec.add_development_dependency "sqlite3"
35
38
  spec.add_development_dependency "selenium-webdriver"
36
39
  spec.add_development_dependency "yard"
40
+ spec.add_development_dependency "rubocop"
37
41
  end
@@ -18,11 +18,12 @@ describe Refile::App do
18
18
  end
19
19
 
20
20
  it "returns a 404 if the file doesn't exist" do
21
- file = Refile.store.upload(StringIO.new("hello"))
21
+ Refile.store.upload(StringIO.new("hello"))
22
22
 
23
23
  get "/store/doesnotexist/hello"
24
24
 
25
25
  expect(last_response.status).to eq(404)
26
+ expect(last_response.content_type).to eq("text/plain;charset=utf-8")
26
27
  expect(last_response.body).to eq("not found")
27
28
  end
28
29
 
@@ -32,12 +33,13 @@ describe Refile::App do
32
33
  get "/doesnotexist/#{file.id}/hello"
33
34
 
34
35
  expect(last_response.status).to eq(404)
36
+ expect(last_response.content_type).to eq("text/plain;charset=utf-8")
35
37
  expect(last_response.body).to eq("not found")
36
38
  end
37
39
 
38
40
  context "with allow origin" do
39
- def app
40
- Refile::App.new(allow_origin: "example.com")
41
+ before(:each) do
42
+ allow(Refile).to receive(:allow_origin).and_return("example.com")
41
43
  end
42
44
 
43
45
  it "sets CORS header" do
@@ -51,12 +53,31 @@ describe Refile::App do
51
53
  end
52
54
  end
53
55
 
56
+ it "returns a 200 for head requests" do
57
+ file = Refile.store.upload(StringIO.new("hello"))
58
+
59
+ head "/store/#{file.id}/hello"
60
+
61
+ expect(last_response.status).to eq(200)
62
+ expect(last_response.body).to be_empty
63
+ end
64
+
65
+ it "returns a 404 for head requests if the file doesn't exist" do
66
+ Refile.store.upload(StringIO.new("hello"))
67
+
68
+ head "/store/doesnotexist/hello"
69
+
70
+ expect(last_response.status).to eq(404)
71
+ expect(last_response.body).to be_empty
72
+ end
73
+
54
74
  it "returns a 404 for non get requests" do
55
75
  file = Refile.store.upload(StringIO.new("hello"))
56
76
 
57
77
  post "/store/#{file.id}/hello"
58
78
 
59
79
  expect(last_response.status).to eq(404)
80
+ expect(last_response.content_type).to eq("text/plain;charset=utf-8")
60
81
  expect(last_response.body).to eq("not found")
61
82
  end
62
83
  end
@@ -68,6 +89,7 @@ describe Refile::App do
68
89
  get "/store/doesnotexist/#{file.id}/hello"
69
90
 
70
91
  expect(last_response.status).to eq(404)
92
+ expect(last_response.content_type).to eq("text/plain;charset=utf-8")
71
93
  expect(last_response.body).to eq("not found")
72
94
  end
73
95
 
@@ -114,6 +136,7 @@ describe Refile::App do
114
136
  post "/store", file: file
115
137
 
116
138
  expect(last_response.status).to eq(404)
139
+ expect(last_response.content_type).to eq("text/plain;charset=utf-8")
117
140
  expect(last_response.body).to eq("not found")
118
141
  end
119
142
 
@@ -130,6 +153,7 @@ describe Refile::App do
130
153
  get "/store"
131
154
 
132
155
  expect(last_response.status).to eq(404)
156
+ expect(last_response.content_type).to eq("text/plain;charset=utf-8")
133
157
  expect(last_response.body).to eq("not found")
134
158
  end
135
159
 
@@ -137,7 +161,7 @@ describe Refile::App do
137
161
  get "/"
138
162
 
139
163
  expect(last_response.status).to eq(404)
164
+ expect(last_response.content_type).to eq("text/plain;charset=utf-8")
140
165
  expect(last_response.body).to eq("not found")
141
166
  end
142
167
  end
143
-