leifcr-refile 0.6.3

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 (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