refile 0.5.5 → 0.6.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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/lib/refile.rb +252 -27
  3. data/lib/refile/app.rb +55 -14
  4. data/lib/refile/attacher.rb +39 -40
  5. data/lib/refile/attachment.rb +28 -13
  6. data/lib/refile/attachment/active_record.rb +90 -1
  7. data/lib/refile/attachment_definition.rb +47 -0
  8. data/lib/refile/backend/s3.rb +1 -147
  9. data/lib/refile/backend_macros.rb +13 -5
  10. data/lib/refile/custom_logger.rb +3 -1
  11. data/lib/refile/file.rb +9 -0
  12. data/lib/refile/image_processing.rb +1 -143
  13. data/lib/refile/rails.rb +30 -0
  14. data/lib/refile/rails/attachment_helper.rb +27 -16
  15. data/lib/refile/signature.rb +5 -0
  16. data/lib/refile/simple_form.rb +17 -0
  17. data/lib/refile/version.rb +1 -1
  18. data/spec/refile/active_record_helper.rb +11 -0
  19. data/spec/refile/app_spec.rb +197 -20
  20. data/spec/refile/attachment/active_record_spec.rb +298 -1
  21. data/spec/refile/attachment_helper_spec.rb +39 -0
  22. data/spec/refile/attachment_spec.rb +53 -5
  23. data/spec/refile/backend_examples.rb +13 -2
  24. data/spec/refile/backend_macros_spec.rb +27 -6
  25. data/spec/refile/custom_logger_spec.rb +2 -3
  26. data/spec/refile/features/direct_upload_spec.rb +18 -0
  27. data/spec/refile/features/multiple_upload_spec.rb +122 -0
  28. data/spec/refile/features/normal_upload_spec.rb +5 -3
  29. data/spec/refile/features/presigned_upload_spec.rb +4 -0
  30. data/spec/refile/features/simple_form_spec.rb +8 -0
  31. data/spec/refile/fixtures/monkey.txt +1 -0
  32. data/spec/refile/fixtures/world.txt +1 -0
  33. data/spec/refile/spec_helper.rb +21 -11
  34. data/spec/refile_spec.rb +253 -24
  35. metadata +12 -303
  36. data/.gitignore +0 -27
  37. data/.rspec +0 -2
  38. data/.rubocop.yml +0 -68
  39. data/.travis.yml +0 -21
  40. data/.yardopts +0 -1
  41. data/CONTRIBUTING.md +0 -33
  42. data/Gemfile +0 -3
  43. data/History.md +0 -96
  44. data/LICENSE.txt +0 -22
  45. data/README.md +0 -651
  46. data/Rakefile +0 -19
  47. data/app/assets/javascripts/refile.js +0 -63
  48. data/config.ru +0 -8
  49. data/config/locales/en.yml +0 -8
  50. data/config/routes.rb +0 -5
  51. data/refile.gemspec +0 -42
  52. data/spec/refile/backend/s3_spec.rb +0 -11
  53. data/spec/refile/test_app.rb +0 -65
  54. data/spec/refile/test_app/app/assets/javascripts/application.js +0 -42
  55. data/spec/refile/test_app/app/controllers/application_controller.rb +0 -2
  56. data/spec/refile/test_app/app/controllers/direct_posts_controller.rb +0 -15
  57. data/spec/refile/test_app/app/controllers/home_controller.rb +0 -4
  58. data/spec/refile/test_app/app/controllers/normal_posts_controller.rb +0 -48
  59. data/spec/refile/test_app/app/controllers/presigned_posts_controller.rb +0 -31
  60. data/spec/refile/test_app/app/models/post.rb +0 -5
  61. data/spec/refile/test_app/app/views/direct_posts/new.html.erb +0 -20
  62. data/spec/refile/test_app/app/views/home/index.html.erb +0 -1
  63. data/spec/refile/test_app/app/views/layouts/application.html.erb +0 -14
  64. data/spec/refile/test_app/app/views/normal_posts/_form.html.erb +0 -28
  65. data/spec/refile/test_app/app/views/normal_posts/edit.html.erb +0 -1
  66. data/spec/refile/test_app/app/views/normal_posts/index.html +0 -5
  67. data/spec/refile/test_app/app/views/normal_posts/new.html.erb +0 -1
  68. data/spec/refile/test_app/app/views/normal_posts/show.html.erb +0 -19
  69. data/spec/refile/test_app/app/views/presigned_posts/new.html.erb +0 -16
  70. data/spec/refile/test_app/config/database.yml +0 -7
  71. data/spec/refile/test_app/config/routes.rb +0 -17
  72. data/spec/refile/test_app/public/favicon.ico +0 -0
@@ -5,8 +5,8 @@ RSpec.shared_examples_for :backend do
5
5
 
6
6
  describe "#upload" do
7
7
  it "raises ArgumentError when invalid object is uploaded" do
8
- expect { backend.upload(double(size: 123)) }.to raise_error(ArgumentError)
9
- expect { backend.upload("hello") }.to raise_error(ArgumentError)
8
+ expect { backend.upload(double(size: 123)) }.to raise_error(Refile::InvalidFile)
9
+ expect { backend.upload("hello") }.to raise_error(Refile::InvalidFile)
10
10
  end
11
11
 
12
12
  it "raises Refile::Invalid when object is too large" do
@@ -177,6 +177,17 @@ RSpec.shared_examples_for :backend do
177
177
  expect { file.read(1, buffer) }.to raise_error
178
178
  end
179
179
 
180
+ describe "#rewind" do
181
+ it "rewinds file to beginning" do
182
+ file = backend.upload(uploadable)
183
+
184
+ expect(file.read(2)).to eq("he")
185
+ expect(file.read(2)).to eq("ll")
186
+ file.rewind
187
+ expect(file.read(2)).to eq("he")
188
+ end
189
+ end
190
+
180
191
  describe "#read" do
181
192
  it "can read file contents" do
182
193
  file = backend.upload(uploadable)
@@ -20,23 +20,27 @@ RSpec.describe Refile::BackendMacros do
20
20
  let(:io) { StringIO.new("hello") }
21
21
 
22
22
  it "works if it conforms to required API" do
23
- expect(instance.upload(double(size: 444, read: io, eof?: true, close: nil))).to be_truthy
23
+ expect(instance.upload(double(size: 444, read: io, eof?: true, rewind: true, close: nil))).to be_truthy
24
24
  end
25
25
 
26
26
  it "raises ArgumentError if argument does not respond to `size`" do
27
- expect { instance.upload(double(read: io, eof?: true, close: nil)) }.to raise_error(ArgumentError)
27
+ expect { instance.upload(double(read: io, eof?: true, rewind: true, close: nil)) }.to raise_error(Refile::InvalidFile)
28
28
  end
29
29
 
30
30
  it "raises ArgumentError if argument does not respond to `read`" do
31
- expect { instance.upload(double(size: 444, eof?: true, close: nil)) }.to raise_error(ArgumentError)
31
+ expect { instance.upload(double(size: 444, eof?: true, rewind: true, close: nil)) }.to raise_error(Refile::InvalidFile)
32
32
  end
33
33
 
34
34
  it "raises ArgumentError if argument does not respond to `eof?`" do
35
- expect { instance.upload(double(size: 444, read: true, close: nil)) }.to raise_error(ArgumentError)
35
+ expect { instance.upload(double(size: 444, read: true, rewind: true, close: nil)) }.to raise_error(Refile::InvalidFile)
36
+ end
37
+
38
+ it "raises ArgumentError if argument does not respond to `rewind`" do
39
+ expect { instance.upload(double(size: 444, read: true, eof?: true, close: nil)) }.to raise_error(Refile::InvalidFile)
36
40
  end
37
41
 
38
42
  it "raises ArgumentError if argument does not respond to `close`" do
39
- expect { instance.upload(double(size: 444, read: true, eof?: true)) }.to raise_error(ArgumentError)
43
+ expect { instance.upload(double(size: 444, read: true, rewind: true, eof?: true)) }.to raise_error(Refile::InvalidFile)
40
44
  end
41
45
 
42
46
  it "returns true if size is respeced" do
@@ -46,7 +50,7 @@ RSpec.describe Refile::BackendMacros do
46
50
 
47
51
  it "raises Refile::Invalid if size is exceeded" do
48
52
  instance.max_size = 8
49
- expect { instance.upload(Refile::FileDouble.new("hello world")) }.to raise_error(Refile::Invalid)
53
+ expect { instance.upload(Refile::FileDouble.new("hello world")) }.to raise_error(Refile::InvalidMaxSize)
50
54
  end
51
55
  end
52
56
 
@@ -59,4 +63,21 @@ RSpec.describe Refile::BackendMacros do
59
63
  expect { instance.get("ev/il") }.to raise_error(Refile::InvalidID)
60
64
  end
61
65
  end
66
+
67
+ describe "#valid_id?" do
68
+ it "returns true for valid ID" do
69
+ expect(klass.valid_id?("1234aBCde123aee")).to be_truthy
70
+ end
71
+
72
+ it "returns false for invalid ID" do
73
+ expect(klass.valid_id?("ev/il")).to be_falsey
74
+ end
75
+ end
76
+
77
+ describe "#decode_id" do
78
+ it "returns to_s" do
79
+ expect(klass.decode_id("1234aBCde123aee")).to eq "1234aBCde123aee"
80
+ expect(klass.decode_id(1234)).to eq "1234"
81
+ end
82
+ end
62
83
  end
@@ -1,4 +1,3 @@
1
- require "active_support/logger"
2
1
  require "refile/custom_logger"
3
2
 
4
3
  describe Refile::CustomLogger do
@@ -12,10 +11,10 @@ describe Refile::CustomLogger do
12
11
  "PATH_INFO" => "/" }
13
12
  end
14
13
 
15
- let(:expected_format) { /^Prefix: \[[^\]]+\] POST "\/" 200 \d+\.\d+ms\n\n$/ }
14
+ let(:expected_format) { %r{Prefix: \[[^\]]+\] POST "/" 200 \d+\.\d+ms\n\n$} }
16
15
 
17
16
  it "uses a dynamic logger" do
18
- _, _, body = described_class.new(rack_app, "Prefix", -> { ActiveSupport::Logger.new(io) }).call(env)
17
+ _, _, body = described_class.new(rack_app, "Prefix", -> { Logger.new(io) }).call(env)
19
18
  body.close
20
19
  expect(io.tap(&:rewind).read).to match(expected_format)
21
20
  end
@@ -9,6 +9,7 @@ feature "Direct HTTP post file uploads", :js do
9
9
  expect(page).to have_content("Upload started")
10
10
  expect(page).to have_content("Upload success")
11
11
  expect(page).to have_content("Upload complete")
12
+ expect(page).to have_content("All uploads complete")
12
13
 
13
14
  click_button "Create"
14
15
 
@@ -28,6 +29,23 @@ feature "Direct HTTP post file uploads", :js do
28
29
  expect(page).to have_content("Upload failure error")
29
30
  end
30
31
 
32
+ scenario "Upload a file after validation failure" do
33
+ visit "/direct/posts/new"
34
+ fill_in "Title", with: "A cool post"
35
+ check "Requires document"
36
+ click_button "Create"
37
+
38
+ attach_file "Document", path("hello.txt")
39
+
40
+ expect(page).to have_content("Upload started")
41
+ expect(page).to have_content("Upload success")
42
+ expect(page).to have_content("Upload complete")
43
+
44
+ click_button "Create"
45
+
46
+ expect(download_link("Document")).to eq("hello")
47
+ end
48
+
31
49
  scenario "Fail to upload a file that has wrong format" do
32
50
  visit "/direct/posts/new"
33
51
  fill_in "Title", with: "A cool post"
@@ -0,0 +1,122 @@
1
+ require "refile/test_app"
2
+
3
+ feature "Multiple file uploads", :js do
4
+ scenario "Upload multiple files" do
5
+ visit "/multiple/posts/new"
6
+ fill_in "Title", with: "A cool post"
7
+ attach_file "Documents", [path("hello.txt"), path("world.txt")]
8
+ click_button "Create"
9
+
10
+ expect(download_link("Document: hello.txt")).to eq("hello")
11
+ expect(download_link("Document: world.txt")).to eq("world")
12
+ end
13
+
14
+ scenario "Fail to upload a file that is too large" do
15
+ visit "/multiple/posts/new"
16
+ fill_in "Title", with: "A cool post"
17
+ attach_file "Documents", [path("hello.txt"), path("large.txt")]
18
+ click_button "Create"
19
+
20
+ expect(page).to have_content("Documents is invalid")
21
+ end
22
+
23
+ scenario "Fail to upload a file that has the wrong format then submit" do
24
+ visit "/multiple/posts/new"
25
+ fill_in "Title", with: "A cool post"
26
+ attach_file "Documents", [path("hello.txt"), path("image.jpg")]
27
+ click_button "Create"
28
+
29
+ expect(page).to have_content("Documents is invalid")
30
+ click_button "Create"
31
+ expect(page).to have_selector("h1", text: "A cool post")
32
+ expect(page).not_to have_link("Document")
33
+ end
34
+
35
+ scenario "Upload files via form redisplay", js: true do
36
+ visit "/multiple/posts/new"
37
+ attach_file "Documents", [path("hello.txt"), path("world.txt")]
38
+ click_button "Create"
39
+ fill_in "Title", with: "A cool post"
40
+ click_button "Create"
41
+
42
+ expect(download_link("Document: hello.txt")).to eq("hello")
43
+ expect(download_link("Document: world.txt")).to eq("world")
44
+ end
45
+
46
+ scenario "Edit with changes" do
47
+ visit "/multiple/posts/new"
48
+ fill_in "Title", with: "A cool post"
49
+ attach_file "Documents", [path("hello.txt"), path("world.txt")]
50
+ click_button "Create"
51
+
52
+ click_link "Edit multiple"
53
+ attach_file "Documents", [path("monkey.txt")]
54
+ click_button "Update"
55
+
56
+ expect(download_link("Document: monkey.txt")).to eq("monkey")
57
+ expect(page).not_to have_link("Document: hello.txt")
58
+ expect(page).not_to have_link("Document: world.txt")
59
+ end
60
+
61
+ scenario "Edit without changes" do
62
+ visit "/multiple/posts/new"
63
+ fill_in "Title", with: "A cool post"
64
+ attach_file "Documents", [path("hello.txt"), path("world.txt")]
65
+ click_button "Create"
66
+
67
+ click_link "Edit multiple"
68
+ click_button "Update"
69
+
70
+ expect(download_link("Document: hello.txt")).to eq("hello")
71
+ expect(download_link("Document: world.txt")).to eq("world")
72
+ end
73
+
74
+ describe "with direct upload" do
75
+ scenario "Successfully upload a file" do
76
+ visit "/direct/posts/new"
77
+ fill_in "Title", with: "A cool post"
78
+ attach_file "Documents", [path("hello.txt"), path("world.txt")]
79
+
80
+ expect(page).to have_content("Upload started")
81
+ expect(page).to have_content("Upload success")
82
+ expect(page).to have_content("Upload complete")
83
+ expect(page).to have_content("All uploads complete")
84
+
85
+ click_button "Create"
86
+
87
+ expect(download_link("Document: hello.txt")).to eq("hello")
88
+ expect(download_link("Document: world.txt")).to eq("world")
89
+ end
90
+ end
91
+
92
+ describe "with presigned upload" do
93
+ scenario "Successfully upload a file" do
94
+ visit "/presigned/posts/new"
95
+ fill_in "Title", with: "A cool post"
96
+ attach_file "Documents", [path("hello.txt"), path("world.txt")]
97
+
98
+ expect(page).to have_content("Presign start")
99
+ expect(page).to have_content("Presign complete")
100
+ expect(page).to have_content("Upload started")
101
+ expect(page).to have_content("Upload complete token accepted")
102
+ expect(page).to have_content("Upload success token accepted")
103
+
104
+ click_button "Create"
105
+
106
+ expect(page).to have_selector("h1", text: "A cool post")
107
+ expect(download_link("Document: hello.txt")).to eq("hello")
108
+ expect(download_link("Document: world.txt")).to eq("world")
109
+ end
110
+
111
+ scenario "Fail to upload a file that is too large" do
112
+ visit "/presigned/posts/new"
113
+ fill_in "Title", with: "A cool post"
114
+ attach_file "Documents", [path("large.txt"), path("world.txt")]
115
+
116
+ expect(page).to have_content("Presign start")
117
+ expect(page).to have_content("Presign complete")
118
+ expect(page).to have_content("Upload started")
119
+ expect(page).to have_content("Upload failure too large")
120
+ end
121
+ end
122
+ end
@@ -119,7 +119,9 @@ feature "Normal HTTP Post file uploads" do
119
119
  end
120
120
 
121
121
  scenario "Upload a file from a remote URL" do
122
- stub_request(:get, "http://www.example.com/some_file").to_return(
122
+ url = "http://www.example.com/foo/bar/some_file.png?some-query-string=true"
123
+
124
+ stub_request(:get, url).to_return(
123
125
  status: 200,
124
126
  body: "abc",
125
127
  headers: {
@@ -130,13 +132,13 @@ feature "Normal HTTP Post file uploads" do
130
132
 
131
133
  visit "/normal/posts/new"
132
134
  fill_in "Title", with: "A cool post"
133
- fill_in "Remote document url", with: "http://www.example.com/some_file"
135
+ fill_in "Remote document url", with: url
134
136
  click_button "Create"
135
137
 
136
138
  expect(page).to have_selector("h1", text: "A cool post")
137
139
  expect(download_link("Document")).to eq("abc")
138
140
  expect(page).to have_selector(".content-type", text: "image/png")
139
141
  expect(page).to have_selector(".size", text: "3")
140
- expect(page).to have_selector(".filename", text: "some_file")
142
+ expect(page).to have_selector(".filename", text: "some_file.png", exact: true)
141
143
  end
142
144
  end
@@ -6,6 +6,8 @@ feature "Direct HTTP post file uploads", :js do
6
6
  fill_in "Title", with: "A cool post"
7
7
  attach_file "Document", path("hello.txt")
8
8
 
9
+ expect(page).to have_content("Presign start")
10
+ expect(page).to have_content("Presign complete")
9
11
  expect(page).to have_content("Upload started")
10
12
  expect(page).to have_content("Upload complete token accepted")
11
13
  expect(page).to have_content("Upload success token accepted")
@@ -21,6 +23,8 @@ feature "Direct HTTP post file uploads", :js do
21
23
  fill_in "Title", with: "A cool post"
22
24
  attach_file "Document", path("large.txt")
23
25
 
26
+ expect(page).to have_content("Presign start")
27
+ expect(page).to have_content("Presign complete")
24
28
  expect(page).to have_content("Upload started")
25
29
  expect(page).to have_content("Upload failure too large")
26
30
  end
@@ -0,0 +1,8 @@
1
+ require "refile/test_app"
2
+
3
+ feature "simple form upload" do
4
+ scenario "renders a normal input" do
5
+ visit "/simple_form/posts/new"
6
+ attach_file "Document", path("hello.txt")
7
+ end
8
+ end
@@ -0,0 +1 @@
1
+ monkey
@@ -0,0 +1 @@
1
+ world
@@ -1,9 +1,13 @@
1
+ ENV["RACK_ENV"] = "test"
2
+
1
3
  require "refile"
2
4
  require "refile/backend_examples"
3
5
  require "webmock/rspec"
4
6
 
5
7
  tmp_path = Dir.mktmpdir
6
8
 
9
+ WebMock.disable_net_connect!(allow_localhost: true)
10
+
7
11
  at_exit do
8
12
  FileUtils.remove_entry_secure(tmp_path)
9
13
  end
@@ -18,9 +22,15 @@ class FakePresignBackend < Refile::Backend::FileSystem
18
22
  end
19
23
  end
20
24
 
25
+ Refile.secret_key = "144c82de680afe5e8e91fc7cf13c22b2f8d2d4b1a4a0e92531979b12e2fa8b6dd6239c65be28517f27f442bfba11572a8bef80acf44a11f465ba85dde85488d5"
26
+
21
27
  Refile.backends["limited_cache"] = FakePresignBackend.new(File.expand_path("default_cache", tmp_path), max_size: 100)
22
28
 
23
- Refile.direct_upload = %w[cache limited_cache]
29
+ Refile.allow_uploads_to = %w[cache limited_cache]
30
+
31
+ Refile.allow_origin = "*"
32
+
33
+ Refile.app_host = "http://localhost:56120"
24
34
 
25
35
  Refile.processor(:reverse) do |file|
26
36
  StringIO.new(file.read.reverse)
@@ -28,6 +38,8 @@ end
28
38
 
29
39
  Refile.processor(:upcase, proc { |file| StringIO.new(file.read.upcase) })
30
40
 
41
+ Refile.logger = Logger.new(nil)
42
+
31
43
  Refile.processor(:concat) do |file, *words|
32
44
  tempfile = Tempfile.new("concat")
33
45
  tempfile.write(file.read)
@@ -38,8 +50,8 @@ Refile.processor(:concat) do |file, *words|
38
50
  File.open(tempfile.path, "r")
39
51
  end
40
52
 
41
- Refile.processor(:convert_case) do |file, format:|
42
- case format
53
+ Refile.processor(:convert_case) do |file, options = {}|
54
+ case options[:format]
43
55
  when "up" then StringIO.new(file.read.upcase)
44
56
  when "down" then StringIO.new(file.read.downcase)
45
57
  else file
@@ -59,6 +71,10 @@ module Refile
59
71
  @io.read(*args)
60
72
  end
61
73
 
74
+ def rewind
75
+ @io.rewind
76
+ end
77
+
62
78
  def size
63
79
  @io.size
64
80
  end
@@ -81,12 +97,6 @@ end
81
97
 
82
98
  RSpec.configure do |config|
83
99
  config.include PathHelper
84
- config.before(:all) do
85
- Refile.logger = Logger.new(nil)
86
- if ENV["S3"]
87
- WebMock.allow_net_connect!
88
- else
89
- WebMock.disable_net_connect!(allow_localhost: true)
90
- end
91
- end
92
100
  end
101
+
102
+ RSpec::Expectations.configuration.warn_about_potential_false_positives = false
@@ -1,6 +1,21 @@
1
1
  require "refile"
2
2
 
3
3
  RSpec.describe Refile do
4
+ before do
5
+ allow(Refile).to receive(:token).and_return("token")
6
+ allow(Refile).to receive(:app_host).and_return(nil)
7
+ allow(Refile).to receive(:mount_point).and_return(nil)
8
+ end
9
+
10
+ let(:klass) do
11
+ Class.new do
12
+ extend Refile::Attachment
13
+ attr_accessor :document_id
14
+ attachment :document
15
+ end
16
+ end
17
+ let(:instance) { klass.new }
18
+
4
19
  describe ".extract_filename" do
5
20
  it "extracts filename from original_filename" do
6
21
  name = Refile.extract_filename(double(original_filename: "/foo/bar/baz.png"))
@@ -40,56 +55,126 @@ RSpec.describe Refile do
40
55
  end
41
56
  end
42
57
 
43
- describe ".attachment_url" do
44
- let(:klass) do
45
- Class.new do
46
- extend Refile::Attachment
47
- attachment :document
48
- end
58
+ describe ".app_url" do
59
+ it "generates a root url when all options unset" do
60
+ expect(Refile.app_url).to eq("/")
49
61
  end
50
- let(:instance) { klass.new }
51
- let(:id) { instance.document_attacher.cache_id }
52
62
 
53
- before do
54
- allow(Refile).to receive(:host).and_return(nil)
55
- allow(Refile).to receive(:mount_point).and_return(nil)
63
+ it "uses supplied host option" do
64
+ expect(Refile.app_url(host: "http://example.org")).to eq("http://example.org/")
65
+ end
66
+
67
+ it "falls back to Refile.app_host" do
68
+ allow(Refile).to receive(:app_host).and_return("http://elabs.se")
69
+
70
+ expect(Refile.app_url).to eq("http://elabs.se/")
71
+ end
72
+
73
+ it "adds a prefix" do
74
+ expect(Refile.app_url(prefix: "/moo")).to eq("/moo")
75
+ end
76
+
77
+ it "takes prefix from Refile.mount_point" do
78
+ allow(Refile).to receive(:mount_point).and_return("/attachments")
79
+ expect(Refile.app_url).to eq("/attachments")
80
+ end
81
+ end
82
+
83
+ describe ".file_url" do
84
+ let(:file) { Refile.cache.upload(Refile::FileDouble.new("hello")) }
85
+ let(:id) { file.id }
86
+
87
+ it "generates a url from an attachment" do
88
+ expect(Refile.file_url(file, filename: "document")).to eq("/token/cache/#{id}/document")
89
+ end
90
+
91
+ it "uses supplied host option" do
92
+ expect(Refile.file_url(file, host: "http://example.org", filename: "document")).to eq("http://example.org/token/cache/#{id}/document")
93
+ end
94
+
95
+ it "falls back to Refile.app_host" do
96
+ allow(Refile).to receive(:app_host).and_return("http://elabs.se")
97
+
98
+ expect(Refile.file_url(file, filename: "document")).to eq("http://elabs.se/token/cache/#{id}/document")
99
+ end
100
+
101
+ it "falls back to Refile.cdn_host" do
102
+ allow(Refile).to receive(:cdn_host).and_return("http://foo.cloudfront.com")
103
+ allow(Refile).to receive(:app_host).and_return("http://elabs.se")
104
+
105
+ expect(Refile.file_url(file, filename: "document")).to eq("http://foo.cloudfront.com/token/cache/#{id}/document")
106
+ end
107
+
108
+ it "adds a prefix" do
109
+ expect(Refile.file_url(file, prefix: "/moo", filename: "document")).to eq("/moo/token/cache/#{id}/document")
56
110
  end
57
111
 
112
+ it "takes prefix from Refile.mount_point" do
113
+ allow(Refile).to receive(:mount_point).and_return("/attachments")
114
+ expect(Refile.file_url(file, filename: "document")).to eq("/attachments/token/cache/#{id}/document")
115
+ end
116
+
117
+ it "adds an escaped filename" do
118
+ expect(Refile.file_url(file, filename: "test.png")).to eq("/token/cache/#{id}/test.png")
119
+ expect(Refile.file_url(file, filename: "tes/t.png")).to eq("/token/cache/#{id}/tes%2Ft.png")
120
+ end
121
+
122
+ it "adds a format" do
123
+ expect(Refile.file_url(file, format: "png", filename: "document")).to eq("/token/cache/#{id}/document.png")
124
+ end
125
+
126
+ context "with no file" do
127
+ it "returns nil" do
128
+ expect(Refile.file_url(nil, filename: "document")).to be_nil
129
+ end
130
+ end
131
+ end
132
+
133
+ describe ".attachment_url" do
134
+ let(:id) { instance.document_attacher.cache_id }
135
+
58
136
  context "with file" do
59
137
  before do
60
138
  instance.document = Refile::FileDouble.new("hello")
61
139
  end
62
140
 
63
141
  it "generates a url from an attachment" do
64
- expect(Refile.attachment_url(instance, :document)).to eq("/cache/#{id}/document")
142
+ expect(Refile.attachment_url(instance, :document)).to eq("/token/cache/#{id}/document")
65
143
  end
66
144
 
67
145
  it "uses supplied host option" do
68
- expect(Refile.attachment_url(instance, :document, host: "http://example.org")).to eq("http://example.org/cache/#{id}/document")
146
+ expect(Refile.attachment_url(instance, :document, host: "http://example.org")).to eq("http://example.org/token/cache/#{id}/document")
69
147
  end
70
148
 
71
- it "falls back to Refile.host" do
72
- allow(Refile).to receive(:host).and_return("http://elabs.se")
149
+ it "falls back to Refile.app_host" do
150
+ allow(Refile).to receive(:app_host).and_return("http://elabs.se")
73
151
 
74
- expect(Refile.attachment_url(instance, :document)).to eq("http://elabs.se/cache/#{id}/document")
152
+ expect(Refile.attachment_url(instance, :document)).to eq("http://elabs.se/token/cache/#{id}/document")
153
+ end
154
+
155
+ it "falls back to Refile.cdn_host" do
156
+ allow(Refile).to receive(:cdn_host).and_return("http://foo.cloudfront.com")
157
+ allow(Refile).to receive(:app_host).and_return("http://elabs.se")
158
+
159
+ expect(Refile.attachment_url(instance, :document)).to eq("http://foo.cloudfront.com/token/cache/#{id}/document")
75
160
  end
76
161
 
77
162
  it "adds a prefix" do
78
- expect(Refile.attachment_url(instance, :document, prefix: "moo")).to eq("/moo/cache/#{id}/document")
163
+ expect(Refile.attachment_url(instance, :document, prefix: "/moo")).to eq("/moo/token/cache/#{id}/document")
79
164
  end
80
165
 
81
166
  it "takes prefix from Refile.mount_point" do
82
- allow(Refile).to receive(:mount_point).and_return("attachments")
83
- expect(Refile.attachment_url(instance, :document)).to eq("/attachments/cache/#{id}/document")
167
+ allow(Refile).to receive(:mount_point).and_return("/attachments")
168
+ expect(Refile.attachment_url(instance, :document)).to eq("/attachments/token/cache/#{id}/document")
84
169
  end
85
170
 
86
171
  it "adds an escaped filename" do
87
- expect(Refile.attachment_url(instance, :document, filename: "test.png")).to eq("/cache/#{id}/test.png")
88
- expect(Refile.attachment_url(instance, :document, filename: "tes/t.png")).to eq("/cache/#{id}/tes%2Ft.png")
172
+ expect(Refile.attachment_url(instance, :document, filename: "test.png")).to eq("/token/cache/#{id}/test.png")
173
+ expect(Refile.attachment_url(instance, :document, filename: "tes/t.png")).to eq("/token/cache/#{id}/tes%2Ft.png")
89
174
  end
90
175
 
91
176
  it "adds a format" do
92
- expect(Refile.attachment_url(instance, :document, format: "png")).to eq("/cache/#{id}/document.png")
177
+ expect(Refile.attachment_url(instance, :document, format: "png")).to eq("/token/cache/#{id}/document.png")
93
178
  end
94
179
  end
95
180
 
@@ -99,7 +184,7 @@ RSpec.describe Refile do
99
184
  end
100
185
 
101
186
  it "adds format inferred from content type" do
102
- expect(Refile.attachment_url(instance, :document)).to eq("/cache/#{id}/document.png")
187
+ expect(Refile.attachment_url(instance, :document)).to eq("/token/cache/#{id}/document.png")
103
188
  end
104
189
  end
105
190
 
@@ -109,7 +194,7 @@ RSpec.describe Refile do
109
194
  end
110
195
 
111
196
  it "adds filename" do
112
- expect(Refile.attachment_url(instance, :document)).to eq("/cache/#{id}/hello.html")
197
+ expect(Refile.attachment_url(instance, :document)).to eq("/token/cache/#{id}/hello.html")
113
198
  end
114
199
  end
115
200
 
@@ -119,4 +204,148 @@ RSpec.describe Refile do
119
204
  end
120
205
  end
121
206
  end
207
+
208
+ describe ".upload_url" do
209
+ it "generates an upload url" do
210
+ expect(Refile.upload_url(Refile.cache)).to eq("/cache")
211
+ end
212
+
213
+ it "uses supplied host option" do
214
+ expect(Refile.upload_url(Refile.cache, host: "http://example.org")).to eq("http://example.org/cache")
215
+ end
216
+
217
+ it "falls back to Refile.app_host" do
218
+ allow(Refile).to receive(:app_host).and_return("http://elabs.se")
219
+
220
+ expect(Refile.upload_url(Refile.cache)).to eq("http://elabs.se/cache")
221
+ end
222
+
223
+ it "does not fall back to Refile.cdn_host" do
224
+ allow(Refile).to receive(:cdn_host).and_return("http://foo.cloudfront.com")
225
+
226
+ expect(Refile.upload_url(Refile.cache)).to eq("/cache")
227
+ end
228
+
229
+ it "adds a prefix" do
230
+ expect(Refile.upload_url(Refile.cache, prefix: "/moo")).to eq("/moo/cache")
231
+ end
232
+
233
+ it "takes prefix from Refile.mount_point" do
234
+ allow(Refile).to receive(:mount_point).and_return("/attachments")
235
+ expect(Refile.upload_url(Refile.cache)).to eq("/attachments/cache")
236
+ end
237
+ end
238
+
239
+ describe ".presign_url" do
240
+ it "generates an upload url" do
241
+ expect(Refile.presign_url(Refile.cache)).to eq("/cache/presign")
242
+ end
243
+
244
+ it "uses supplied host option" do
245
+ expect(Refile.presign_url(Refile.cache, host: "http://example.org")).to eq("http://example.org/cache/presign")
246
+ end
247
+
248
+ it "falls back to Refile.app_host" do
249
+ allow(Refile).to receive(:app_host).and_return("http://elabs.se")
250
+
251
+ expect(Refile.presign_url(Refile.cache)).to eq("http://elabs.se/cache/presign")
252
+ end
253
+
254
+ it "does not fall back to Refile.cdn_host" do
255
+ allow(Refile).to receive(:cdn_host).and_return("http://foo.cloudfront.com")
256
+
257
+ expect(Refile.presign_url(Refile.cache)).to eq("/cache/presign")
258
+ end
259
+
260
+ it "adds a prefix" do
261
+ expect(Refile.presign_url(Refile.cache, prefix: "/moo")).to eq("/moo/cache/presign")
262
+ end
263
+
264
+ it "takes prefix from Refile.mount_point" do
265
+ allow(Refile).to receive(:mount_point).and_return("/attachments")
266
+ expect(Refile.presign_url(Refile.cache)).to eq("/attachments/cache/presign")
267
+ end
268
+ end
269
+
270
+ describe ".attachment_upload_url" do
271
+ it "generates an upload url" do
272
+ expect(Refile.attachment_upload_url(instance, :document)).to eq("/cache")
273
+ end
274
+
275
+ it "uses supplied host option" do
276
+ expect(Refile.attachment_upload_url(instance, :document, host: "http://example.org")).to eq("http://example.org/cache")
277
+ end
278
+
279
+ it "falls back to Refile.app_host" do
280
+ allow(Refile).to receive(:app_host).and_return("http://elabs.se")
281
+
282
+ expect(Refile.attachment_upload_url(instance, :document)).to eq("http://elabs.se/cache")
283
+ end
284
+
285
+ it "does not fall back to Refile.cdn_host" do
286
+ allow(Refile).to receive(:cdn_host).and_return("http://foo.cloudfront.com")
287
+
288
+ expect(Refile.attachment_upload_url(instance, :document)).to eq("/cache")
289
+ end
290
+
291
+ it "adds a prefix" do
292
+ expect(Refile.attachment_upload_url(instance, :document, prefix: "/moo")).to eq("/moo/cache")
293
+ end
294
+
295
+ it "takes prefix from Refile.mount_point" do
296
+ allow(Refile).to receive(:mount_point).and_return("/attachments")
297
+ expect(Refile.attachment_upload_url(instance, :document)).to eq("/attachments/cache")
298
+ end
299
+ end
300
+
301
+ describe ".attachment_presign_url" do
302
+ it "generates an upload url" do
303
+ expect(Refile.attachment_presign_url(instance, :document)).to eq("/cache/presign")
304
+ end
305
+
306
+ it "uses supplied host option" do
307
+ expect(Refile.attachment_presign_url(instance, :document, host: "http://example.org")).to eq("http://example.org/cache/presign")
308
+ end
309
+
310
+ it "falls back to Refile.app_host" do
311
+ allow(Refile).to receive(:app_host).and_return("http://elabs.se")
312
+
313
+ expect(Refile.attachment_presign_url(instance, :document)).to eq("http://elabs.se/cache/presign")
314
+ end
315
+
316
+ it "does not fall back to Refile.cdn_host" do
317
+ allow(Refile).to receive(:cdn_host).and_return("http://foo.cloudfront.com")
318
+
319
+ expect(Refile.attachment_presign_url(instance, :document)).to eq("/cache/presign")
320
+ end
321
+
322
+ it "adds a prefix" do
323
+ expect(Refile.attachment_presign_url(instance, :document, prefix: "/moo")).to eq("/moo/cache/presign")
324
+ end
325
+
326
+ it "takes prefix from Refile.mount_point" do
327
+ allow(Refile).to receive(:mount_point).and_return("/attachments")
328
+ expect(Refile.attachment_presign_url(instance, :document)).to eq("/attachments/cache/presign")
329
+ end
330
+ end
331
+
332
+ describe ".token" do
333
+ before do
334
+ allow(Refile).to receive(:token).and_call_original
335
+ end
336
+
337
+ it "returns digest of given path and secret token" do
338
+ allow(Refile).to receive(:secret_key).and_return("abcd1234")
339
+
340
+ path = "/store/f5f2e4/document.pdf"
341
+ token = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha1"), "abcd1234", path)
342
+ expect(Refile.token(path)).to eq(token)
343
+ end
344
+
345
+ it "returns raise error when secret token is nil" do
346
+ allow(Refile).to receive(:secret_key).and_return(nil)
347
+
348
+ expect { Refile.token("/store/f5f2e4/document.pdf") }.to raise_error(RuntimeError, /Refile\.secret_key was not set/)
349
+ end
350
+ end
122
351
  end