leifcr-refile 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/app/assets/javascripts/refile.js +125 -0
  3. data/config/locales/en.yml +10 -0
  4. data/config/routes.rb +5 -0
  5. data/lib/refile.rb +510 -0
  6. data/lib/refile/app.rb +186 -0
  7. data/lib/refile/attacher.rb +190 -0
  8. data/lib/refile/attachment.rb +108 -0
  9. data/lib/refile/attachment/active_record.rb +133 -0
  10. data/lib/refile/attachment_definition.rb +83 -0
  11. data/lib/refile/backend/file_system.rb +120 -0
  12. data/lib/refile/backend/s3.rb +1 -0
  13. data/lib/refile/backend_macros.rb +45 -0
  14. data/lib/refile/custom_logger.rb +48 -0
  15. data/lib/refile/file.rb +102 -0
  16. data/lib/refile/file_double.rb +13 -0
  17. data/lib/refile/image_processing.rb +1 -0
  18. data/lib/refile/rails.rb +54 -0
  19. data/lib/refile/rails/attachment_helper.rb +121 -0
  20. data/lib/refile/random_hasher.rb +11 -0
  21. data/lib/refile/signature.rb +36 -0
  22. data/lib/refile/simple_form.rb +17 -0
  23. data/lib/refile/type.rb +28 -0
  24. data/lib/refile/version.rb +3 -0
  25. data/spec/refile/active_record_helper.rb +35 -0
  26. data/spec/refile/app_spec.rb +424 -0
  27. data/spec/refile/attachment/active_record_spec.rb +568 -0
  28. data/spec/refile/attachment_helper_spec.rb +78 -0
  29. data/spec/refile/attachment_spec.rb +589 -0
  30. data/spec/refile/backend/file_system_spec.rb +5 -0
  31. data/spec/refile/backend_examples.rb +228 -0
  32. data/spec/refile/backend_macros_spec.rb +83 -0
  33. data/spec/refile/custom_logger_spec.rb +21 -0
  34. data/spec/refile/features/direct_upload_spec.rb +63 -0
  35. data/spec/refile/features/multiple_upload_spec.rb +122 -0
  36. data/spec/refile/features/normal_upload_spec.rb +144 -0
  37. data/spec/refile/features/presigned_upload_spec.rb +31 -0
  38. data/spec/refile/features/simple_form_spec.rb +8 -0
  39. data/spec/refile/fixtures/hello.txt +1 -0
  40. data/spec/refile/fixtures/image.jpg +0 -0
  41. data/spec/refile/fixtures/large.txt +44 -0
  42. data/spec/refile/fixtures/monkey.txt +1 -0
  43. data/spec/refile/fixtures/world.txt +1 -0
  44. data/spec/refile/spec_helper.rb +72 -0
  45. data/spec/refile_spec.rb +355 -0
  46. metadata +143 -0
@@ -0,0 +1,144 @@
1
+ require "refile/test_app"
2
+
3
+ feature "Normal HTTP Post file uploads" do
4
+ scenario "Successfully upload a file" do
5
+ visit "/normal/posts/new"
6
+ fill_in "Title", with: "A cool post"
7
+ attach_file "Document", path("hello.txt")
8
+ click_button "Create"
9
+
10
+ expect(page).to have_selector("h1", text: "A cool post")
11
+ expect(page).to have_selector(".content-type", text: "text/plain")
12
+ expect(page).to have_selector(".size", text: "6")
13
+ expect(page).to have_selector(".filename", text: "hello.txt")
14
+ expect(download_link("Document")).to eq("hello")
15
+ end
16
+
17
+ scenario "Fail to upload a file that is too large" do
18
+ visit "/normal/posts/new"
19
+ fill_in "Title", with: "A cool post"
20
+ attach_file "Document", path("large.txt")
21
+ click_button "Create"
22
+
23
+ expect(page).to have_selector(".field_with_errors")
24
+ expect(page).to have_content("Document is too large")
25
+ end
26
+
27
+ scenario "Fail to upload a file that has the wrong format" do
28
+ visit "/normal/posts/new"
29
+ fill_in "Title", with: "A cool post"
30
+ attach_file "Image", path("hello.txt")
31
+ click_button "Create"
32
+
33
+ expect(page).to have_selector(".field_with_errors")
34
+ expect(page).to have_content("You are not allowed to upload text/plain file format. Allowed types: image/jpeg, image/gif, and image/png.")
35
+ end
36
+
37
+ scenario "Fail to upload a file that has the wrong format then submit" do
38
+ visit "/normal/posts/new"
39
+ fill_in "Title", with: "A cool post"
40
+ attach_file "Image", path("hello.txt")
41
+ click_button "Create"
42
+
43
+ expect(page).to have_selector(".field_with_errors")
44
+ expect(page).to have_content("You are not allowed to upload text/plain file format. Allowed types: image/jpeg, image/gif, and image/png.")
45
+ click_button "Create"
46
+ expect(page).to have_selector("h1", text: "A cool post")
47
+ expect(page).not_to have_link("Document")
48
+ end
49
+
50
+ scenario "Successfully update a record with an attached file" do
51
+ visit "/normal/posts/new"
52
+ fill_in "Title", with: "A cool post"
53
+ attach_file "Image", path("image.jpg")
54
+ click_button "Create"
55
+
56
+ expect(page).to have_selector("h1", text: "A cool post")
57
+ click_link("Edit")
58
+
59
+ fill_in "Title", with: "A very cool post"
60
+
61
+ click_button "Update"
62
+ expect(page).to have_selector("h1", text: "A very cool post")
63
+ end
64
+
65
+ # FIXME: the only reason this is js:true is because the rack_test driver
66
+ # doesn't submit file+metadata correctly.
67
+ scenario "Upload a file via form redisplay", js: true do
68
+ visit "/normal/posts/new"
69
+ attach_file "Document", path("hello.txt")
70
+ click_button "Create"
71
+ fill_in "Title", with: "A cool post"
72
+ click_button "Create"
73
+
74
+ expect(page).to have_selector("h1", text: "A cool post")
75
+ expect(page).to have_selector(".content-type", text: "text/plain")
76
+ expect(page).to have_selector(".size", text: "6")
77
+ expect(page).to have_selector(".filename", text: "hello.txt")
78
+ expect(download_link("Document")).to eq("hello")
79
+ end
80
+
81
+ scenario "Format conversion" do
82
+ visit "/normal/posts/new"
83
+ fill_in "Title", with: "A cool post"
84
+ attach_file "Document", path("hello.txt")
85
+ click_button "Create"
86
+
87
+ expect(page).to have_selector("h1", text: "A cool post")
88
+ expect(download_link("Convert to Upper")).to eq("HELLO")
89
+ end
90
+
91
+ scenario "Successfully remove an uploaded file" do
92
+ visit "/normal/posts/new"
93
+ fill_in "Title", with: "A cool post"
94
+ attach_file "Document", path("hello.txt")
95
+ click_button "Create"
96
+
97
+ expect(page).to have_selector("h1", text: "A cool post")
98
+ expect(page).to have_selector(:link, "Document")
99
+ click_link("Edit")
100
+
101
+ check "Remove document"
102
+ click_button "Update"
103
+ expect(page).to have_selector("h1", text: "A cool post")
104
+ expect(page).not_to have_selector(:link, "Document")
105
+ expect(page).not_to have_selector(".content-type", text: "text/plain")
106
+ expect(page).not_to have_selector(".size", text: "6")
107
+ expect(page).not_to have_selector(".filename", text: "hello.txt")
108
+ end
109
+
110
+ scenario "Successfully remove a record with an uploaded file" do
111
+ visit "/normal/posts/new"
112
+ fill_in "Title", with: "A cool post about to be deleted"
113
+ attach_file "Document", path("hello.txt")
114
+ click_button "Create"
115
+
116
+ expect(page).to have_selector("h1", text: "A cool post about to be deleted")
117
+ click_link("Delete")
118
+ expect(page).to_not have_content("A cool post about to be deleted")
119
+ end
120
+
121
+ scenario "Upload a file from a remote URL" do
122
+ url = "http://www.example.com/foo/bar/some_file.png?some-query-string=true"
123
+
124
+ stub_request(:get, url).to_return(
125
+ status: 200,
126
+ body: "abc",
127
+ headers: {
128
+ "Content-Length" => 3,
129
+ "Content-Type" => "image/png"
130
+ }
131
+ )
132
+
133
+ visit "/normal/posts/new"
134
+ fill_in "Title", with: "A cool post"
135
+ fill_in "Remote document url", with: url
136
+ click_button "Create"
137
+
138
+ expect(page).to have_selector("h1", text: "A cool post")
139
+ expect(download_link("Document")).to eq("abc")
140
+ expect(page).to have_selector(".content-type", text: "image/png")
141
+ expect(page).to have_selector(".size", text: "3")
142
+ expect(page).to have_selector(".filename", text: "some_file.png", exact: true)
143
+ end
144
+ end
@@ -0,0 +1,31 @@
1
+ require "refile/test_app"
2
+
3
+ feature "Direct HTTP post file uploads", :js do
4
+ scenario "Successfully upload a file" do
5
+ visit "/presigned/posts/new"
6
+ fill_in "Title", with: "A cool post"
7
+ attach_file "Document", path("hello.txt")
8
+
9
+ expect(page).to have_content("Presign start")
10
+ expect(page).to have_content("Presign complete")
11
+ expect(page).to have_content("Upload started")
12
+ expect(page).to have_content("Upload complete token accepted")
13
+ expect(page).to have_content("Upload success token accepted")
14
+
15
+ click_button "Create"
16
+
17
+ expect(page).to have_selector("h1", text: "A cool post")
18
+ expect(download_link("Document")).to eq("hello")
19
+ end
20
+
21
+ scenario "Fail to upload a file that is too large" do
22
+ visit "/presigned/posts/new"
23
+ fill_in "Title", with: "A cool post"
24
+ attach_file "Document", path("large.txt")
25
+
26
+ expect(page).to have_content("Presign start")
27
+ expect(page).to have_content("Presign complete")
28
+ expect(page).to have_content("Upload started")
29
+ expect(page).to have_content("Upload failure too large")
30
+ end
31
+ 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
+ hello
@@ -0,0 +1,44 @@
1
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec massa arcu,
2
+ convallis a tellus vitae, placerat rhoncus nisi. Nullam molestie volutpat
3
+ turpis vitae viverra. Integer nulla nisl, dictum et rutrum quis, auctor ut dui.
4
+ Nulla imperdiet ante a lorem molestie tempor. Suspendisse pharetra in mauris
5
+ mollis dapibus. Nullam pretium fringilla justo, faucibus condimentum elit
6
+ rutrum ac. Vivamus sem justo, congue id lobortis nec, viverra ac lacus. Donec
7
+ eu vestibulum risus, at efficitur nisl. Maecenas sed elit a dui malesuada
8
+ ultricies at eget est. Duis lobortis tincidunt pellentesque.
9
+
10
+ Quisque in nisl felis. Quisque a neque nec diam posuere mattis. Donec a nibh
11
+ cursus, tempus est iaculis, gravida odio. Pellentesque eleifend enim eget
12
+ placerat dignissim. Cum sociis natoque penatibus et magnis dis parturient
13
+ montes, nascetur ridiculus mus. In non ex in augue feugiat convallis. Duis
14
+ varius at sapien vitae molestie. Suspendisse sit amet aliquet quam, quis
15
+ condimentum nibh.
16
+
17
+ Donec a quam quis ipsum imperdiet semper. In ac scelerisque elit, non fermentum
18
+ nisl. Nulla dapibus velit eget ullamcorper blandit. Maecenas justo diam,
19
+ porttitor eget nunc dictum, sollicitudin lacinia lectus. Pellentesque non augue
20
+ urna. In felis ipsum, posuere vitae sapien non, aliquet maximus nibh.
21
+ Suspendisse potenti. Aenean venenatis euismod congue. Praesent quis ullamcorper
22
+ sapien. In hac habitasse platea dictumst. Morbi semper augue dapibus, posuere
23
+ justo sit amet, convallis felis. Vivamus condimentum elementum ex, quis rhoncus
24
+ purus pulvinar et. Nunc vel risus sem. Suspendisse porttitor convallis massa,
25
+ molestie sollicitudin metus semper a. Donec ac cursus tortor. Nam felis nulla,
26
+ pretium eu tempus at, euismod eu erat.
27
+
28
+ Donec vel tempus augue. Pellentesque sit amet ante in odio malesuada facilisis
29
+ nec sit amet turpis. Donec vitae iaculis mauris. Aenean venenatis interdum
30
+ quam, nec tincidunt mauris aliquam vel. Nunc ultrices arcu euismod velit
31
+ ultricies, id laoreet arcu venenatis. Donec euismod scelerisque magna, nec
32
+ interdum lorem ornare nec. Morbi blandit volutpat velit, consequat maximus
33
+ justo mattis non. In pellentesque malesuada consectetur. Cras convallis mi ut
34
+ nibh rutrum ullamcorper. Nam finibus consequat erat a feugiat. Donec laoreet
35
+ risus eget enim interdum dictum. Duis orci lectus, scelerisque tempus volutpat
36
+ eget, ullamcorper eu felis. Aliquam tempor in dui sit amet dapibus. Nulla sed
37
+ metus vestibulum, dignissim odio et, dapibus eros. Praesent semper arcu ut
38
+ augue suscipit, ac ornare tortor auctor. Suspendisse a velit dui.
39
+
40
+ Etiam nec est ut ex laoreet iaculis vel id enim. Vivamus ac hendrerit leo.
41
+ Vestibulum auctor nibh nec arcu rhoncus, a condimentum quam accumsan. Ut justo
42
+ augue, laoreet at bibendum vel, aliquet vitae est. Aliquam accumsan ac diam nec
43
+ pretium. Nulla dictum velit nec elementum mollis. Interdum et malesuada fames
44
+ ac ante ipsum primis in faucibus.
@@ -0,0 +1 @@
1
+ monkey
@@ -0,0 +1 @@
1
+ world
@@ -0,0 +1,72 @@
1
+ ENV["RACK_ENV"] = "test"
2
+
3
+ require "refile"
4
+ require "refile/backend_examples"
5
+ require "webmock/rspec"
6
+ require "refile/file_double"
7
+
8
+ tmp_path = Dir.mktmpdir
9
+
10
+ WebMock.disable_net_connect!(allow_localhost: true)
11
+
12
+ at_exit do
13
+ FileUtils.remove_entry_secure(tmp_path)
14
+ end
15
+
16
+ Refile.store = Refile::Backend::FileSystem.new(File.expand_path("default_store", tmp_path))
17
+ Refile.cache = Refile::Backend::FileSystem.new(File.expand_path("default_cache", tmp_path))
18
+
19
+ class FakePresignBackend < Refile::Backend::FileSystem
20
+ def presign
21
+ id = Refile::RandomHasher.new.hash
22
+ Refile::Signature.new(as: "file", id: id, url: "/presigned/posts/upload", fields: { id: id, token: "xyz123" })
23
+ end
24
+ end
25
+
26
+ Refile.secret_key = "144c82de680afe5e8e91fc7cf13c22b2f8d2d4b1a4a0e92531979b12e2fa8b6dd6239c65be28517f27f442bfba11572a8bef80acf44a11f465ba85dde85488d5"
27
+
28
+ Refile.backends["limited_cache"] = FakePresignBackend.new(File.expand_path("default_cache", tmp_path), max_size: 100)
29
+
30
+ Refile.allow_uploads_to = %w[cache limited_cache]
31
+
32
+ Refile.allow_origin = "*"
33
+
34
+ Refile.app_host = "http://localhost:56120"
35
+
36
+ Refile.processor(:reverse) do |file|
37
+ StringIO.new(file.read.reverse)
38
+ end
39
+
40
+ Refile.processor(:upcase, proc { |file| StringIO.new(file.read.upcase) })
41
+
42
+ Refile.logger = Logger.new(nil)
43
+
44
+ Refile.processor(:concat) do |file, *words|
45
+ tempfile = Tempfile.new("concat")
46
+ tempfile.write(file.read)
47
+ words.each do |word|
48
+ tempfile.write(word)
49
+ end
50
+ tempfile.close
51
+ File.open(tempfile.path, "r")
52
+ end
53
+
54
+ Refile.processor(:convert_case) do |file, options = {}|
55
+ case options[:format]
56
+ when "up" then StringIO.new(file.read.upcase)
57
+ when "down" then StringIO.new(file.read.downcase)
58
+ else file
59
+ end
60
+ end
61
+
62
+ module PathHelper
63
+ def path(filename)
64
+ File.expand_path(File.join("fixtures", filename), File.dirname(__FILE__))
65
+ end
66
+ end
67
+
68
+ RSpec.configure do |config|
69
+ config.include PathHelper
70
+ end
71
+
72
+ RSpec::Expectations.configuration.warn_about_potential_false_positives = false
@@ -0,0 +1,355 @@
1
+ require "refile"
2
+
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
+
19
+ describe ".extract_filename" do
20
+ it "extracts filename from original_filename" do
21
+ name = Refile.extract_filename(double(original_filename: "/foo/bar/baz.png"))
22
+ expect(name).to eq("baz.png")
23
+ end
24
+
25
+ it "extracts filename from path" do
26
+ name = Refile.extract_filename(double(path: "/foo/bar/baz.png"))
27
+ expect(name).to eq("baz.png")
28
+ end
29
+
30
+ it "returns nil if it can't determine filename" do
31
+ name = Refile.extract_filename(double)
32
+ expect(name).to be_nil
33
+ end
34
+ end
35
+
36
+ describe ".extract_content_type" do
37
+ it "extracts content type" do
38
+ name = Refile.extract_content_type(double(content_type: "image/jpeg"))
39
+ expect(name).to eq("image/jpeg")
40
+ end
41
+
42
+ it "extracts content type from extension" do
43
+ name = Refile.extract_content_type(double(original_filename: "test.png"))
44
+ expect(name).to eq("image/png")
45
+ end
46
+
47
+ it "returns nil if it can't determine content type" do
48
+ name = Refile.extract_filename(double)
49
+ expect(name).to be_nil
50
+ end
51
+
52
+ it "returns nil if it has an unknown content type" do
53
+ name = Refile.extract_content_type(double(original_filename: "foo.blah"))
54
+ expect(name).to be_nil
55
+ end
56
+ end
57
+
58
+ describe ".app_url" do
59
+ it "generates a root url when all options unset" do
60
+ expect(Refile.app_url).to eq("/")
61
+ end
62
+
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")
110
+ end
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
+ it "avoids extension duplication by specifying format" do
127
+ expect(Refile.file_url(file, format: "png", filename: "document.png")).to eq("/token/cache/#{id}/document.png")
128
+ end
129
+
130
+ context "with no file" do
131
+ it "returns nil" do
132
+ expect(Refile.file_url(nil, filename: "document")).to be_nil
133
+ end
134
+ end
135
+ end
136
+
137
+ describe ".attachment_url" do
138
+ let(:id) { instance.document_attacher.cache_id }
139
+
140
+ context "with file" do
141
+ before do
142
+ instance.document = Refile::FileDouble.new("hello")
143
+ end
144
+
145
+ it "generates a url from an attachment" do
146
+ expect(Refile.attachment_url(instance, :document)).to eq("/token/cache/#{id}/document")
147
+ end
148
+
149
+ it "uses supplied host option" do
150
+ expect(Refile.attachment_url(instance, :document, host: "http://example.org")).to eq("http://example.org/token/cache/#{id}/document")
151
+ end
152
+
153
+ it "falls back to Refile.app_host" do
154
+ allow(Refile).to receive(:app_host).and_return("http://elabs.se")
155
+
156
+ expect(Refile.attachment_url(instance, :document)).to eq("http://elabs.se/token/cache/#{id}/document")
157
+ end
158
+
159
+ it "falls back to Refile.cdn_host" do
160
+ allow(Refile).to receive(:cdn_host).and_return("http://foo.cloudfront.com")
161
+ allow(Refile).to receive(:app_host).and_return("http://elabs.se")
162
+
163
+ expect(Refile.attachment_url(instance, :document)).to eq("http://foo.cloudfront.com/token/cache/#{id}/document")
164
+ end
165
+
166
+ it "adds a prefix" do
167
+ expect(Refile.attachment_url(instance, :document, prefix: "/moo")).to eq("/moo/token/cache/#{id}/document")
168
+ end
169
+
170
+ it "takes prefix from Refile.mount_point" do
171
+ allow(Refile).to receive(:mount_point).and_return("/attachments")
172
+ expect(Refile.attachment_url(instance, :document)).to eq("/attachments/token/cache/#{id}/document")
173
+ end
174
+
175
+ it "adds an escaped filename" do
176
+ expect(Refile.attachment_url(instance, :document, filename: "test.png")).to eq("/token/cache/#{id}/test.png")
177
+ expect(Refile.attachment_url(instance, :document, filename: "tes/t.png")).to eq("/token/cache/#{id}/tes%2Ft.png")
178
+ end
179
+
180
+ it "adds a format" do
181
+ expect(Refile.attachment_url(instance, :document, format: "png")).to eq("/token/cache/#{id}/document.png")
182
+ end
183
+ end
184
+
185
+ context "with file with content type" do
186
+ before do
187
+ instance.document = Refile::FileDouble.new("hello", content_type: "image/png")
188
+ end
189
+
190
+ it "adds format inferred from content type" do
191
+ expect(Refile.attachment_url(instance, :document)).to eq("/token/cache/#{id}/document.png")
192
+ end
193
+ end
194
+
195
+ context "with file with filename" do
196
+ before do
197
+ instance.document = Refile::FileDouble.new("hello", "hello.html")
198
+ end
199
+
200
+ it "adds filename" do
201
+ expect(Refile.attachment_url(instance, :document)).to eq("/token/cache/#{id}/hello.html")
202
+ end
203
+ end
204
+
205
+ context "with no file" do
206
+ it "returns nil" do
207
+ expect(Refile.attachment_url(instance, :document)).to be_nil
208
+ end
209
+ end
210
+ end
211
+
212
+ describe ".upload_url" do
213
+ it "generates an upload url" do
214
+ expect(Refile.upload_url(Refile.cache)).to eq("/cache")
215
+ end
216
+
217
+ it "uses supplied host option" do
218
+ expect(Refile.upload_url(Refile.cache, host: "http://example.org")).to eq("http://example.org/cache")
219
+ end
220
+
221
+ it "falls back to Refile.app_host" do
222
+ allow(Refile).to receive(:app_host).and_return("http://elabs.se")
223
+
224
+ expect(Refile.upload_url(Refile.cache)).to eq("http://elabs.se/cache")
225
+ end
226
+
227
+ it "does not fall back to Refile.cdn_host" do
228
+ allow(Refile).to receive(:cdn_host).and_return("http://foo.cloudfront.com")
229
+
230
+ expect(Refile.upload_url(Refile.cache)).to eq("/cache")
231
+ end
232
+
233
+ it "adds a prefix" do
234
+ expect(Refile.upload_url(Refile.cache, prefix: "/moo")).to eq("/moo/cache")
235
+ end
236
+
237
+ it "takes prefix from Refile.mount_point" do
238
+ allow(Refile).to receive(:mount_point).and_return("/attachments")
239
+ expect(Refile.upload_url(Refile.cache)).to eq("/attachments/cache")
240
+ end
241
+ end
242
+
243
+ describe ".presign_url" do
244
+ it "generates an upload url" do
245
+ expect(Refile.presign_url(Refile.cache)).to eq("/cache/presign")
246
+ end
247
+
248
+ it "uses supplied host option" do
249
+ expect(Refile.presign_url(Refile.cache, host: "http://example.org")).to eq("http://example.org/cache/presign")
250
+ end
251
+
252
+ it "falls back to Refile.app_host" do
253
+ allow(Refile).to receive(:app_host).and_return("http://elabs.se")
254
+
255
+ expect(Refile.presign_url(Refile.cache)).to eq("http://elabs.se/cache/presign")
256
+ end
257
+
258
+ it "does not fall back to Refile.cdn_host" do
259
+ allow(Refile).to receive(:cdn_host).and_return("http://foo.cloudfront.com")
260
+
261
+ expect(Refile.presign_url(Refile.cache)).to eq("/cache/presign")
262
+ end
263
+
264
+ it "adds a prefix" do
265
+ expect(Refile.presign_url(Refile.cache, prefix: "/moo")).to eq("/moo/cache/presign")
266
+ end
267
+
268
+ it "takes prefix from Refile.mount_point" do
269
+ allow(Refile).to receive(:mount_point).and_return("/attachments")
270
+ expect(Refile.presign_url(Refile.cache)).to eq("/attachments/cache/presign")
271
+ end
272
+ end
273
+
274
+ describe ".attachment_upload_url" do
275
+ it "generates an upload url" do
276
+ expect(Refile.attachment_upload_url(instance, :document)).to eq("/cache")
277
+ end
278
+
279
+ it "uses supplied host option" do
280
+ expect(Refile.attachment_upload_url(instance, :document, host: "http://example.org")).to eq("http://example.org/cache")
281
+ end
282
+
283
+ it "falls back to Refile.app_host" do
284
+ allow(Refile).to receive(:app_host).and_return("http://elabs.se")
285
+
286
+ expect(Refile.attachment_upload_url(instance, :document)).to eq("http://elabs.se/cache")
287
+ end
288
+
289
+ it "does not fall back to Refile.cdn_host" do
290
+ allow(Refile).to receive(:cdn_host).and_return("http://foo.cloudfront.com")
291
+
292
+ expect(Refile.attachment_upload_url(instance, :document)).to eq("/cache")
293
+ end
294
+
295
+ it "adds a prefix" do
296
+ expect(Refile.attachment_upload_url(instance, :document, prefix: "/moo")).to eq("/moo/cache")
297
+ end
298
+
299
+ it "takes prefix from Refile.mount_point" do
300
+ allow(Refile).to receive(:mount_point).and_return("/attachments")
301
+ expect(Refile.attachment_upload_url(instance, :document)).to eq("/attachments/cache")
302
+ end
303
+ end
304
+
305
+ describe ".attachment_presign_url" do
306
+ it "generates an upload url" do
307
+ expect(Refile.attachment_presign_url(instance, :document)).to eq("/cache/presign")
308
+ end
309
+
310
+ it "uses supplied host option" do
311
+ expect(Refile.attachment_presign_url(instance, :document, host: "http://example.org")).to eq("http://example.org/cache/presign")
312
+ end
313
+
314
+ it "falls back to Refile.app_host" do
315
+ allow(Refile).to receive(:app_host).and_return("http://elabs.se")
316
+
317
+ expect(Refile.attachment_presign_url(instance, :document)).to eq("http://elabs.se/cache/presign")
318
+ end
319
+
320
+ it "does not fall back to Refile.cdn_host" do
321
+ allow(Refile).to receive(:cdn_host).and_return("http://foo.cloudfront.com")
322
+
323
+ expect(Refile.attachment_presign_url(instance, :document)).to eq("/cache/presign")
324
+ end
325
+
326
+ it "adds a prefix" do
327
+ expect(Refile.attachment_presign_url(instance, :document, prefix: "/moo")).to eq("/moo/cache/presign")
328
+ end
329
+
330
+ it "takes prefix from Refile.mount_point" do
331
+ allow(Refile).to receive(:mount_point).and_return("/attachments")
332
+ expect(Refile.attachment_presign_url(instance, :document)).to eq("/attachments/cache/presign")
333
+ end
334
+ end
335
+
336
+ describe ".token" do
337
+ before do
338
+ allow(Refile).to receive(:token).and_call_original
339
+ end
340
+
341
+ it "returns digest of given path and secret token" do
342
+ allow(Refile).to receive(:secret_key).and_return("abcd1234")
343
+
344
+ path = "/store/f5f2e4/document.pdf"
345
+ token = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha1"), "abcd1234", path)
346
+ expect(Refile.token(path)).to eq(token)
347
+ end
348
+
349
+ it "returns raise error when secret token is nil" do
350
+ allow(Refile).to receive(:secret_key).and_return(nil)
351
+
352
+ expect { Refile.token("/store/f5f2e4/document.pdf") }.to raise_error(RuntimeError, /Refile\.secret_key was not set/)
353
+ end
354
+ end
355
+ end