paperclip_jk 5.0.0.beta2

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 (190) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +21 -0
  3. data/.hound.yml +1066 -0
  4. data/.rubocop.yml +1 -0
  5. data/.travis.yml +26 -0
  6. data/Appraisals +27 -0
  7. data/CONTRIBUTING.md +86 -0
  8. data/Gemfile +15 -0
  9. data/LICENSE +24 -0
  10. data/NEWS +424 -0
  11. data/README.md +999 -0
  12. data/RELEASING.md +17 -0
  13. data/Rakefile +44 -0
  14. data/UPGRADING +17 -0
  15. data/features/basic_integration.feature +81 -0
  16. data/features/migration.feature +70 -0
  17. data/features/rake_tasks.feature +62 -0
  18. data/features/step_definitions/attachment_steps.rb +110 -0
  19. data/features/step_definitions/html_steps.rb +15 -0
  20. data/features/step_definitions/rails_steps.rb +230 -0
  21. data/features/step_definitions/s3_steps.rb +14 -0
  22. data/features/step_definitions/web_steps.rb +107 -0
  23. data/features/support/env.rb +11 -0
  24. data/features/support/fakeweb.rb +13 -0
  25. data/features/support/file_helpers.rb +34 -0
  26. data/features/support/fixtures/boot_config.txt +15 -0
  27. data/features/support/fixtures/gemfile.txt +5 -0
  28. data/features/support/fixtures/preinitializer.txt +20 -0
  29. data/features/support/paths.rb +28 -0
  30. data/features/support/rails.rb +63 -0
  31. data/features/support/selectors.rb +19 -0
  32. data/gemfiles/4.2.awsv2.0.gemfile +17 -0
  33. data/gemfiles/4.2.awsv2.1.gemfile +17 -0
  34. data/gemfiles/4.2.awsv2.gemfile +20 -0
  35. data/gemfiles/5.0.awsv2.0.gemfile +17 -0
  36. data/gemfiles/5.0.awsv2.1.gemfile +17 -0
  37. data/gemfiles/5.0.awsv2.gemfile +25 -0
  38. data/lib/generators/paperclip/USAGE +8 -0
  39. data/lib/generators/paperclip/paperclip_generator.rb +30 -0
  40. data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +15 -0
  41. data/lib/paperclip.rb +211 -0
  42. data/lib/paperclip/attachment.rb +610 -0
  43. data/lib/paperclip/attachment_registry.rb +60 -0
  44. data/lib/paperclip/callbacks.rb +42 -0
  45. data/lib/paperclip/content_type_detector.rb +80 -0
  46. data/lib/paperclip/errors.rb +34 -0
  47. data/lib/paperclip/file_command_content_type_detector.rb +30 -0
  48. data/lib/paperclip/filename_cleaner.rb +16 -0
  49. data/lib/paperclip/geometry.rb +158 -0
  50. data/lib/paperclip/geometry_detector_factory.rb +48 -0
  51. data/lib/paperclip/geometry_parser_factory.rb +31 -0
  52. data/lib/paperclip/glue.rb +17 -0
  53. data/lib/paperclip/has_attached_file.rb +115 -0
  54. data/lib/paperclip/helpers.rb +60 -0
  55. data/lib/paperclip/interpolations.rb +197 -0
  56. data/lib/paperclip/interpolations/plural_cache.rb +18 -0
  57. data/lib/paperclip/io_adapters/abstract_adapter.rb +47 -0
  58. data/lib/paperclip/io_adapters/attachment_adapter.rb +36 -0
  59. data/lib/paperclip/io_adapters/data_uri_adapter.rb +22 -0
  60. data/lib/paperclip/io_adapters/empty_string_adapter.rb +18 -0
  61. data/lib/paperclip/io_adapters/file_adapter.rb +22 -0
  62. data/lib/paperclip/io_adapters/http_url_proxy_adapter.rb +15 -0
  63. data/lib/paperclip/io_adapters/identity_adapter.rb +12 -0
  64. data/lib/paperclip/io_adapters/nil_adapter.rb +34 -0
  65. data/lib/paperclip/io_adapters/registry.rb +32 -0
  66. data/lib/paperclip/io_adapters/stringio_adapter.rb +33 -0
  67. data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +42 -0
  68. data/lib/paperclip/io_adapters/uri_adapter.rb +44 -0
  69. data/lib/paperclip/locales/en.yml +18 -0
  70. data/lib/paperclip/logger.rb +21 -0
  71. data/lib/paperclip/matchers.rb +64 -0
  72. data/lib/paperclip/matchers/have_attached_file_matcher.rb +54 -0
  73. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +100 -0
  74. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +59 -0
  75. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +96 -0
  76. data/lib/paperclip/media_type_spoof_detector.rb +89 -0
  77. data/lib/paperclip/missing_attachment_styles.rb +79 -0
  78. data/lib/paperclip/processor.rb +48 -0
  79. data/lib/paperclip/processor_helpers.rb +50 -0
  80. data/lib/paperclip/rails_environment.rb +25 -0
  81. data/lib/paperclip/railtie.rb +31 -0
  82. data/lib/paperclip/schema.rb +77 -0
  83. data/lib/paperclip/storage.rb +4 -0
  84. data/lib/paperclip/storage/database.rb +140 -0
  85. data/lib/paperclip/storage/filesystem.rb +90 -0
  86. data/lib/paperclip/storage/fog.rb +244 -0
  87. data/lib/paperclip/storage/s3.rb +442 -0
  88. data/lib/paperclip/style.rb +109 -0
  89. data/lib/paperclip/tempfile.rb +43 -0
  90. data/lib/paperclip/tempfile_factory.rb +23 -0
  91. data/lib/paperclip/thumbnail.rb +121 -0
  92. data/lib/paperclip/url_generator.rb +72 -0
  93. data/lib/paperclip/validators.rb +74 -0
  94. data/lib/paperclip/validators/attachment_content_type_validator.rb +88 -0
  95. data/lib/paperclip/validators/attachment_file_name_validator.rb +80 -0
  96. data/lib/paperclip/validators/attachment_file_type_ignorance_validator.rb +29 -0
  97. data/lib/paperclip/validators/attachment_presence_validator.rb +30 -0
  98. data/lib/paperclip/validators/attachment_size_validator.rb +109 -0
  99. data/lib/paperclip/validators/media_type_spoof_detection_validator.rb +27 -0
  100. data/lib/paperclip/version.rb +3 -0
  101. data/lib/tasks/paperclip.rake +127 -0
  102. data/paperclip.gemspec +54 -0
  103. data/shoulda_macros/paperclip.rb +134 -0
  104. data/spec/database.yml +4 -0
  105. data/spec/paperclip/attachment_definitions_spec.rb +13 -0
  106. data/spec/paperclip/attachment_processing_spec.rb +80 -0
  107. data/spec/paperclip/attachment_registry_spec.rb +158 -0
  108. data/spec/paperclip/attachment_spec.rb +1517 -0
  109. data/spec/paperclip/content_type_detector_spec.rb +48 -0
  110. data/spec/paperclip/file_command_content_type_detector_spec.rb +26 -0
  111. data/spec/paperclip/filename_cleaner_spec.rb +14 -0
  112. data/spec/paperclip/geometry_detector_spec.rb +39 -0
  113. data/spec/paperclip/geometry_parser_spec.rb +73 -0
  114. data/spec/paperclip/geometry_spec.rb +255 -0
  115. data/spec/paperclip/glue_spec.rb +44 -0
  116. data/spec/paperclip/has_attached_file_spec.rb +158 -0
  117. data/spec/paperclip/integration_spec.rb +668 -0
  118. data/spec/paperclip/interpolations_spec.rb +262 -0
  119. data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +78 -0
  120. data/spec/paperclip/io_adapters/attachment_adapter_spec.rb +139 -0
  121. data/spec/paperclip/io_adapters/data_uri_adapter_spec.rb +83 -0
  122. data/spec/paperclip/io_adapters/empty_string_adapter_spec.rb +17 -0
  123. data/spec/paperclip/io_adapters/file_adapter_spec.rb +131 -0
  124. data/spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb +113 -0
  125. data/spec/paperclip/io_adapters/identity_adapter_spec.rb +8 -0
  126. data/spec/paperclip/io_adapters/nil_adapter_spec.rb +25 -0
  127. data/spec/paperclip/io_adapters/registry_spec.rb +35 -0
  128. data/spec/paperclip/io_adapters/stringio_adapter_spec.rb +64 -0
  129. data/spec/paperclip/io_adapters/uploaded_file_adapter_spec.rb +146 -0
  130. data/spec/paperclip/io_adapters/uri_adapter_spec.rb +102 -0
  131. data/spec/paperclip/matchers/have_attached_file_matcher_spec.rb +19 -0
  132. data/spec/paperclip/matchers/validate_attachment_content_type_matcher_spec.rb +109 -0
  133. data/spec/paperclip/matchers/validate_attachment_presence_matcher_spec.rb +69 -0
  134. data/spec/paperclip/matchers/validate_attachment_size_matcher_spec.rb +88 -0
  135. data/spec/paperclip/media_type_spoof_detector_spec.rb +70 -0
  136. data/spec/paperclip/meta_class_spec.rb +30 -0
  137. data/spec/paperclip/paperclip_missing_attachment_styles_spec.rb +84 -0
  138. data/spec/paperclip/paperclip_spec.rb +192 -0
  139. data/spec/paperclip/plural_cache_spec.rb +37 -0
  140. data/spec/paperclip/processor_helpers_spec.rb +57 -0
  141. data/spec/paperclip/processor_spec.rb +26 -0
  142. data/spec/paperclip/rails_environment_spec.rb +33 -0
  143. data/spec/paperclip/rake_spec.rb +103 -0
  144. data/spec/paperclip/schema_spec.rb +248 -0
  145. data/spec/paperclip/storage/filesystem_spec.rb +79 -0
  146. data/spec/paperclip/storage/fog_spec.rb +545 -0
  147. data/spec/paperclip/storage/s3_live_spec.rb +186 -0
  148. data/spec/paperclip/storage/s3_spec.rb +1583 -0
  149. data/spec/paperclip/style_spec.rb +255 -0
  150. data/spec/paperclip/tempfile_factory_spec.rb +33 -0
  151. data/spec/paperclip/thumbnail_spec.rb +500 -0
  152. data/spec/paperclip/url_generator_spec.rb +211 -0
  153. data/spec/paperclip/validators/attachment_content_type_validator_spec.rb +322 -0
  154. data/spec/paperclip/validators/attachment_file_name_validator_spec.rb +160 -0
  155. data/spec/paperclip/validators/attachment_presence_validator_spec.rb +85 -0
  156. data/spec/paperclip/validators/attachment_size_validator_spec.rb +235 -0
  157. data/spec/paperclip/validators/media_type_spoof_detection_validator_spec.rb +52 -0
  158. data/spec/paperclip/validators_spec.rb +164 -0
  159. data/spec/spec_helper.rb +45 -0
  160. data/spec/support/assertions.rb +78 -0
  161. data/spec/support/fake_model.rb +25 -0
  162. data/spec/support/fake_rails.rb +12 -0
  163. data/spec/support/fixtures/12k.png +0 -0
  164. data/spec/support/fixtures/50x50.png +0 -0
  165. data/spec/support/fixtures/5k.png +0 -0
  166. data/spec/support/fixtures/animated +0 -0
  167. data/spec/support/fixtures/animated.gif +0 -0
  168. data/spec/support/fixtures/animated.unknown +0 -0
  169. data/spec/support/fixtures/bad.png +1 -0
  170. data/spec/support/fixtures/empty.html +1 -0
  171. data/spec/support/fixtures/empty.xlsx +0 -0
  172. data/spec/support/fixtures/fog.yml +8 -0
  173. data/spec/support/fixtures/rotated.jpg +0 -0
  174. data/spec/support/fixtures/s3.yml +8 -0
  175. data/spec/support/fixtures/spaced file.jpg +0 -0
  176. data/spec/support/fixtures/spaced file.png +0 -0
  177. data/spec/support/fixtures/text.txt +1 -0
  178. data/spec/support/fixtures/twopage.pdf +0 -0
  179. data/spec/support/fixtures/uppercase.PNG +0 -0
  180. data/spec/support/matchers/accept.rb +5 -0
  181. data/spec/support/matchers/exist.rb +5 -0
  182. data/spec/support/matchers/have_column.rb +23 -0
  183. data/spec/support/mock_attachment.rb +22 -0
  184. data/spec/support/mock_interpolator.rb +24 -0
  185. data/spec/support/mock_url_generator_builder.rb +27 -0
  186. data/spec/support/model_reconstruction.rb +68 -0
  187. data/spec/support/reporting.rb +11 -0
  188. data/spec/support/test_data.rb +13 -0
  189. data/spec/support/version_helper.rb +9 -0
  190. metadata +713 -0
@@ -0,0 +1,79 @@
1
+ require 'spec_helper'
2
+
3
+ describe Paperclip::Storage::Filesystem do
4
+ context "Filesystem" do
5
+ context "normal file" do
6
+ before do
7
+ rebuild_model styles: { thumbnail: "25x25#" }
8
+ @dummy = Dummy.create!
9
+
10
+ @file = File.open(fixture_file('5k.png'))
11
+ @dummy.avatar = @file
12
+ end
13
+
14
+ after { @file.close }
15
+
16
+ it "allows file assignment" do
17
+ assert @dummy.save
18
+ end
19
+
20
+ it "stores the original" do
21
+ @dummy.save
22
+ assert_file_exists(@dummy.avatar.path)
23
+ end
24
+
25
+ it "stores the thumbnail" do
26
+ @dummy.save
27
+ assert_file_exists(@dummy.avatar.path(:thumbnail))
28
+ end
29
+
30
+ it "is rewinded after flush_writes" do
31
+ @dummy.avatar.instance_eval "def after_flush_writes; end"
32
+
33
+ files = @dummy.avatar.queued_for_write.values
34
+ @dummy.save
35
+ assert files.none?(&:eof?), "Expect all the files to be rewinded."
36
+ end
37
+
38
+ it "is removed after after_flush_writes" do
39
+ paths = @dummy.avatar.queued_for_write.values.map(&:path)
40
+ @dummy.save
41
+ assert paths.none?{ |path| File.exist?(path) },
42
+ "Expect all the files to be deleted."
43
+ end
44
+
45
+ it 'copies the file to a known location with copy_to_local_file' do
46
+ tempfile = Tempfile.new("known_location")
47
+ @dummy.avatar.copy_to_local_file(:original, tempfile.path)
48
+ tempfile.rewind
49
+ assert_equal @file.read, tempfile.read
50
+ tempfile.close
51
+ end
52
+ end
53
+
54
+ context "with file that has space in file name" do
55
+ before do
56
+ rebuild_model styles: { thumbnail: "25x25#" }
57
+ @dummy = Dummy.create!
58
+
59
+ @file = File.open(fixture_file('spaced file.png'))
60
+ @dummy.avatar = @file
61
+ @dummy.save
62
+ end
63
+
64
+ after { @file.close }
65
+
66
+ it "stores the file" do
67
+ assert_file_exists(@dummy.avatar.path)
68
+ end
69
+
70
+ it "returns a replaced version for path" do
71
+ assert_match /.+\/spaced_file\.png/, @dummy.avatar.path
72
+ end
73
+
74
+ it "returns a replaced version for url" do
75
+ assert_match /.+\/spaced_file\.png/, @dummy.avatar.url
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,545 @@
1
+ require 'spec_helper'
2
+ require 'fog/aws'
3
+ require 'fog/local'
4
+ require 'timecop'
5
+
6
+ describe Paperclip::Storage::Fog do
7
+ context "" do
8
+ before { Fog.mock! }
9
+
10
+ context "with credentials provided in a path string" do
11
+ before do
12
+ rebuild_model styles: { medium: "300x300>", thumb: "100x100>" },
13
+ storage: :fog,
14
+ url: '/:attachment/:filename',
15
+ fog_directory: "paperclip",
16
+ fog_credentials: fixture_file('fog.yml')
17
+ @file = File.new(fixture_file('5k.png'), 'rb')
18
+ @dummy = Dummy.new
19
+ @dummy.avatar = @file
20
+ end
21
+
22
+ after { @file.close }
23
+
24
+ it "has the proper information loading credentials from a file" do
25
+ assert_equal @dummy.avatar.fog_credentials[:provider], 'AWS'
26
+ end
27
+ end
28
+
29
+ context "with credentials provided in a File object" do
30
+ before do
31
+ rebuild_model styles: { medium: "300x300>", thumb: "100x100>" },
32
+ storage: :fog,
33
+ url: '/:attachment/:filename',
34
+ fog_directory: "paperclip",
35
+ fog_credentials: File.open(fixture_file('fog.yml'))
36
+ @file = File.new(fixture_file('5k.png'), 'rb')
37
+ @dummy = Dummy.new
38
+ @dummy.avatar = @file
39
+ end
40
+
41
+ after { @file.close }
42
+
43
+ it "has the proper information loading credentials from a file" do
44
+ assert_equal @dummy.avatar.fog_credentials[:provider], 'AWS'
45
+ end
46
+ end
47
+
48
+ context "with default values for path and url" do
49
+ before do
50
+ rebuild_model styles: { medium: "300x300>", thumb: "100x100>" },
51
+ storage: :fog,
52
+ url: '/:attachment/:filename',
53
+ fog_directory: "paperclip",
54
+ fog_credentials: {
55
+ provider: 'AWS',
56
+ aws_access_key_id: 'AWS_ID',
57
+ aws_secret_access_key: 'AWS_SECRET'
58
+ }
59
+ @file = File.new(fixture_file('5k.png'), 'rb')
60
+ @dummy = Dummy.new
61
+ @dummy.avatar = @file
62
+ end
63
+
64
+ after { @file.close }
65
+
66
+ it "is able to interpolate the path without blowing up" do
67
+ assert_equal File.expand_path(File.join(File.dirname(__FILE__), "../../../tmp/public/avatars/5k.png")),
68
+ @dummy.avatar.path
69
+ end
70
+ end
71
+
72
+ context "with no path or url given and using defaults" do
73
+ before do
74
+ rebuild_model styles: { medium: "300x300>", thumb: "100x100>" },
75
+ storage: :fog,
76
+ fog_directory: "paperclip",
77
+ fog_credentials: {
78
+ provider: 'AWS',
79
+ aws_access_key_id: 'AWS_ID',
80
+ aws_secret_access_key: 'AWS_SECRET'
81
+ }
82
+ @file = File.new(fixture_file('5k.png'), 'rb')
83
+ @dummy = Dummy.new
84
+ @dummy.id = 1
85
+ @dummy.avatar = @file
86
+ end
87
+
88
+ after { @file.close }
89
+
90
+ it "has correct path and url from interpolated defaults" do
91
+ assert_equal "dummies/avatars/000/000/001/original/5k.png", @dummy.avatar.path
92
+ end
93
+ end
94
+
95
+ context "with file params provided as lambda" do
96
+ before do
97
+ fog_file = lambda{ |a| { custom_header: a.instance.custom_method }}
98
+ klass = rebuild_model storage: :fog,
99
+ fog_file: fog_file
100
+
101
+ klass.class_eval do
102
+ def custom_method
103
+ 'foobar'
104
+ end
105
+ end
106
+
107
+
108
+ @dummy = Dummy.new
109
+ end
110
+
111
+ it "is able to evaluate correct values for file headers" do
112
+ assert_equal @dummy.avatar.send(:fog_file), { custom_header: 'foobar' }
113
+ end
114
+ end
115
+
116
+ before do
117
+ @fog_directory = 'papercliptests'
118
+
119
+ @credentials = {
120
+ provider: 'AWS',
121
+ aws_access_key_id: 'ID',
122
+ aws_secret_access_key: 'SECRET'
123
+ }
124
+
125
+ @connection = Fog::Storage.new(@credentials)
126
+ @connection.directories.create(
127
+ key: @fog_directory
128
+ )
129
+
130
+ @options = {
131
+ fog_directory: @fog_directory,
132
+ fog_credentials: @credentials,
133
+ fog_host: nil,
134
+ fog_file: {cache_control: 1234},
135
+ path: ":attachment/:basename:dotextension",
136
+ storage: :fog
137
+ }
138
+
139
+ rebuild_model(@options)
140
+ end
141
+
142
+ it "is extended by the Fog module" do
143
+ assert Dummy.new.avatar.is_a?(Paperclip::Storage::Fog)
144
+ end
145
+
146
+ context "when assigned" do
147
+ before do
148
+ @file = File.new(fixture_file('5k.png'), 'rb')
149
+ @dummy = Dummy.new
150
+ @dummy.avatar = @file
151
+ end
152
+
153
+ after do
154
+ @file.close
155
+ directory = @connection.directories.new(key: @fog_directory)
156
+ directory.files.each {|file| file.destroy}
157
+ directory.destroy
158
+ end
159
+
160
+ it "is rewound after flush_writes" do
161
+ @dummy.avatar.instance_eval "def after_flush_writes; end"
162
+
163
+ files = @dummy.avatar.queued_for_write.values
164
+ @dummy.save
165
+ assert files.none?(&:eof?), "Expect all the files to be rewinded."
166
+ end
167
+
168
+ it "is removed after after_flush_writes" do
169
+ paths = @dummy.avatar.queued_for_write.values.map(&:path)
170
+ @dummy.save
171
+ assert paths.none?{ |path| File.exist?(path) },
172
+ "Expect all the files to be deleted."
173
+ end
174
+
175
+ it 'is able to be copied to a local file' do
176
+ @dummy.save
177
+ tempfile = Tempfile.new("known_location")
178
+ tempfile.binmode
179
+ @dummy.avatar.copy_to_local_file(:original, tempfile.path)
180
+ tempfile.rewind
181
+ assert_equal @connection.directories.get(@fog_directory).files.get(@dummy.avatar.path).body,
182
+ tempfile.read
183
+ tempfile.close
184
+ end
185
+
186
+ it 'is able to be handled when missing while copying to a local file' do
187
+ tempfile = Tempfile.new("known_location")
188
+ tempfile.binmode
189
+ assert_equal false, @dummy.avatar.copy_to_local_file(:original, tempfile.path)
190
+ tempfile.close
191
+ end
192
+
193
+ it "passes the content type to the Fog::Storage::AWS::Files instance" do
194
+ Fog::Storage::AWS::Files.any_instance.expects(:create).with do |hash|
195
+ hash[:content_type]
196
+ end
197
+ @dummy.save
198
+ end
199
+
200
+ context "without a bucket" do
201
+ before do
202
+ @connection.directories.get(@fog_directory).destroy
203
+ end
204
+
205
+ it "creates the bucket" do
206
+ assert @dummy.save
207
+ assert @connection.directories.get(@fog_directory)
208
+ end
209
+ end
210
+
211
+ context "with a bucket" do
212
+ it "succeeds" do
213
+ assert @dummy.save
214
+ end
215
+ end
216
+
217
+ context "without a fog_host" do
218
+ before do
219
+ rebuild_model(@options.merge(fog_host: nil))
220
+ @dummy = Dummy.new
221
+ @dummy.avatar = StringIO.new('.')
222
+ @dummy.save
223
+ end
224
+
225
+ it "provides a public url" do
226
+ assert !@dummy.avatar.url.nil?
227
+ end
228
+ end
229
+
230
+ context "with a fog_host" do
231
+ before do
232
+ rebuild_model(@options.merge(fog_host: 'http://example.com'))
233
+ @dummy = Dummy.new
234
+ @dummy.avatar = StringIO.new(".\n")
235
+ @dummy.save
236
+ end
237
+
238
+ it "provides a public url" do
239
+ expect(@dummy.avatar.url).to match(/^http:\/\/example\.com\/avatars\/data\?\d*$/)
240
+ end
241
+ end
242
+
243
+ context "with a fog_host that includes a wildcard placeholder" do
244
+ before do
245
+ rebuild_model(
246
+ fog_directory: @fog_directory,
247
+ fog_credentials: @credentials,
248
+ fog_host: 'http://img%d.example.com',
249
+ path: ":attachment/:basename:dotextension",
250
+ storage: :fog
251
+ )
252
+ @dummy = Dummy.new
253
+ @dummy.avatar = StringIO.new(".\n")
254
+ @dummy.save
255
+ end
256
+
257
+ it "provides a public url" do
258
+ expect(@dummy.avatar.url).to match(/^http:\/\/img[0123]\.example\.com\/avatars\/data\?\d*$/)
259
+ end
260
+ end
261
+
262
+ context "with fog_public set to false" do
263
+ before do
264
+ rebuild_model(@options.merge(fog_public: false))
265
+ @dummy = Dummy.new
266
+ @dummy.avatar = StringIO.new('.')
267
+ @dummy.save
268
+ end
269
+
270
+ it 'sets the @fog_public instance variable to false' do
271
+ assert_equal false, @dummy.avatar.instance_variable_get('@options')[:fog_public]
272
+ assert_equal false, @dummy.avatar.fog_public
273
+ end
274
+ end
275
+
276
+ context "with styles set and fog_public set to false" do
277
+ before do
278
+ rebuild_model(@options.merge(fog_public: false, styles: { medium: "300x300>", thumb: "100x100>" }))
279
+ @file = File.new(fixture_file('5k.png'), 'rb')
280
+ @dummy = Dummy.new
281
+ @dummy.avatar = @file
282
+ @dummy.save
283
+ end
284
+
285
+ it 'sets the @fog_public for a particular style to false' do
286
+ assert_equal false, @dummy.avatar.instance_variable_get('@options')[:fog_public]
287
+ assert_equal false, @dummy.avatar.fog_public(:thumb)
288
+ end
289
+ end
290
+
291
+ context "with styles set and fog_public set per-style" do
292
+ before do
293
+ rebuild_model(@options.merge(fog_public: { medium: false, thumb: true}, styles: { medium: "300x300>", thumb: "100x100>" }))
294
+ @file = File.new(fixture_file('5k.png'), 'rb')
295
+ @dummy = Dummy.new
296
+ @dummy.avatar = @file
297
+ @dummy.save
298
+ end
299
+
300
+ it 'sets the fog_public for a particular style to correct value' do
301
+ assert_equal false, @dummy.avatar.fog_public(:medium)
302
+ assert_equal true, @dummy.avatar.fog_public(:thumb)
303
+ end
304
+ end
305
+
306
+ context "with fog_public not set" do
307
+ before do
308
+ rebuild_model(@options)
309
+ @dummy = Dummy.new
310
+ @dummy.avatar = StringIO.new('.')
311
+ @dummy.save
312
+ end
313
+
314
+ it "defaults fog_public to true" do
315
+ assert_equal true, @dummy.avatar.fog_public
316
+ end
317
+ end
318
+
319
+ context "with scheme set" do
320
+ before do
321
+ rebuild_model(@options.merge(:fog_credentials => @credentials.merge(:scheme => 'http')))
322
+ @file = File.new(fixture_file('5k.png'), 'rb')
323
+ @dummy = Dummy.new
324
+ @dummy.avatar = @file
325
+ @dummy.save
326
+ end
327
+
328
+ it "honors the scheme in public url" do
329
+ assert_match(/^http:\/\//, @dummy.avatar.url)
330
+ end
331
+ it "honors the scheme in expiring url" do
332
+ assert_match(/^http:\/\//, @dummy.avatar.expiring_url)
333
+ end
334
+ end
335
+
336
+ context "with scheme not set" do
337
+ before do
338
+ rebuild_model(@options)
339
+ @file = File.new(fixture_file('5k.png'), 'rb')
340
+ @dummy = Dummy.new
341
+ @dummy.avatar = @file
342
+ @dummy.save
343
+ end
344
+
345
+ it "provides HTTPS public url" do
346
+ assert_match(/^https:\/\//, @dummy.avatar.url)
347
+ end
348
+ it "provides HTTPS expiring url" do
349
+ assert_match(/^https:\/\//, @dummy.avatar.expiring_url)
350
+ end
351
+ end
352
+
353
+ context "with a valid bucket name for a subdomain" do
354
+ before { @dummy.stubs(:new_record?).returns(false) }
355
+
356
+ it "provides an url in subdomain style" do
357
+ assert_match(/^https:\/\/papercliptests.s3.amazonaws.com\/avatars\/5k.png/, @dummy.avatar.url)
358
+ end
359
+
360
+ it "provides an url that expires in subdomain style" do
361
+ assert_match(/^https:\/\/papercliptests.s3.amazonaws.com\/avatars\/5k.png.+Expires=.+$/, @dummy.avatar.expiring_url)
362
+ end
363
+ end
364
+
365
+ context "generating an expiring url" do
366
+ it "generates the same url when using Times and Integer offsets" do
367
+ Timecop.freeze do
368
+ offset = 1234
369
+ rebuild_model(@options)
370
+ dummy = Dummy.new
371
+ dummy.avatar = StringIO.new('.')
372
+
373
+ assert_equal dummy.avatar.expiring_url(offset),
374
+ dummy.avatar.expiring_url(Time.now + offset )
375
+ end
376
+ end
377
+
378
+ it 'matches the default url if there is no assignment' do
379
+ dummy = Dummy.new
380
+ assert_equal dummy.avatar.url, dummy.avatar.expiring_url
381
+ end
382
+
383
+ it 'matches the default url when given a style if there is no assignment' do
384
+ dummy = Dummy.new
385
+ assert_equal dummy.avatar.url(:thumb), dummy.avatar.expiring_url(3600, :thumb)
386
+ end
387
+ end
388
+
389
+ context "with an invalid bucket name for a subdomain" do
390
+ before do
391
+ rebuild_model(@options.merge(fog_directory: "this_is_invalid"))
392
+ @dummy = Dummy.new
393
+ @dummy.avatar = @file
394
+ @dummy.save
395
+ end
396
+
397
+ it "does not match the bucket-subdomain restrictions" do
398
+ invalid_subdomains = %w(this_is_invalid in iamareallylongbucketnameiamareallylongbucketnameiamareallylongbu invalid- inval..id inval-.id inval.-id -invalid 192.168.10.2)
399
+ invalid_subdomains.each do |name|
400
+ assert_no_match Paperclip::Storage::Fog::AWS_BUCKET_SUBDOMAIN_RESTRICTON_REGEX, name
401
+ end
402
+ end
403
+
404
+ it "provides an url in folder style" do
405
+ assert_match(/^https:\/\/s3.amazonaws.com\/this_is_invalid\/avatars\/5k.png\?\d*$/, @dummy.avatar.url)
406
+ end
407
+
408
+ it "provides a url that expires in folder style" do
409
+ assert_match(/^https:\/\/s3.amazonaws.com\/this_is_invalid\/avatars\/5k.png.+Expires=.+$/, @dummy.avatar.expiring_url)
410
+ end
411
+
412
+ end
413
+
414
+ context "with a proc for a bucket name evaluating a model method" do
415
+ before do
416
+ @dynamic_fog_directory = 'dynamicpaperclip'
417
+ rebuild_model(@options.merge(fog_directory: lambda { |attachment| attachment.instance.bucket_name }))
418
+ @dummy = Dummy.new
419
+ @dummy.stubs(:bucket_name).returns(@dynamic_fog_directory)
420
+ @dummy.avatar = @file
421
+ @dummy.save
422
+ end
423
+
424
+ it "has created the bucket" do
425
+ assert @connection.directories.get(@dynamic_fog_directory).inspect
426
+ end
427
+
428
+ it "provides an url using dynamic bucket name" do
429
+ assert_match(/^https:\/\/dynamicpaperclip.s3.amazonaws.com\/avatars\/5k.png\?\d*$/, @dummy.avatar.url)
430
+ end
431
+ end
432
+
433
+ context "with a proc for the fog_host evaluating a model method" do
434
+ before do
435
+ rebuild_model(@options.merge(fog_host: lambda { |attachment| attachment.instance.fog_host }))
436
+ @dummy = Dummy.new
437
+ @dummy.stubs(:fog_host).returns('http://dynamicfoghost.com')
438
+ @dummy.avatar = @file
439
+ @dummy.save
440
+ end
441
+
442
+ it "provides a public url" do
443
+ assert_match(/http:\/\/dynamicfoghost\.com/, @dummy.avatar.url)
444
+ end
445
+
446
+ end
447
+
448
+ context "with a custom fog_host" do
449
+ before do
450
+ rebuild_model(@options.merge(fog_host: "http://dynamicfoghost.com"))
451
+ @dummy = Dummy.new
452
+ @dummy.avatar = @file
453
+ @dummy.save
454
+ end
455
+
456
+ it "provides a public url" do
457
+ assert_match(/http:\/\/dynamicfoghost\.com/, @dummy.avatar.url)
458
+ end
459
+
460
+ it "provides an expiring url" do
461
+ assert_match(/http:\/\/dynamicfoghost\.com/, @dummy.avatar.expiring_url)
462
+ end
463
+
464
+ context "with an invalid bucket name for a subdomain" do
465
+ before do
466
+ rebuild_model(@options.merge({fog_directory: "this_is_invalid", fog_host: "http://dynamicfoghost.com"}))
467
+ @dummy = Dummy.new
468
+ @dummy.avatar = @file
469
+ @dummy.save
470
+ end
471
+
472
+ it "provides an expiring url" do
473
+ assert_match(/http:\/\/dynamicfoghost\.com/, @dummy.avatar.expiring_url)
474
+ end
475
+ end
476
+
477
+ end
478
+
479
+ context "with a proc for the fog_credentials evaluating a model method" do
480
+ before do
481
+ @dynamic_fog_credentials = {
482
+ provider: 'AWS',
483
+ aws_access_key_id: 'DYNAMIC_ID',
484
+ aws_secret_access_key: 'DYNAMIC_SECRET'
485
+ }
486
+ rebuild_model(@options.merge(fog_credentials: lambda { |attachment| attachment.instance.fog_credentials }))
487
+ @dummy = Dummy.new
488
+ @dummy.stubs(:fog_credentials).returns(@dynamic_fog_credentials)
489
+ @dummy.avatar = @file
490
+ @dummy.save
491
+ end
492
+
493
+ it "provides a public url" do
494
+ assert_equal @dummy.avatar.fog_credentials, @dynamic_fog_credentials
495
+ end
496
+ end
497
+
498
+ context "with custom fog_options" do
499
+ before do
500
+ rebuild_model(
501
+ @options.merge(fog_options: { multipart_chunk_size: 104857600 }),
502
+ )
503
+ @dummy = Dummy.new
504
+ @dummy.avatar = @file
505
+ end
506
+
507
+ it "applies the options to the fog #create call" do
508
+ files = stub
509
+ @dummy.avatar.stubs(:directory).returns stub(files: files)
510
+ files.expects(:create).with(
511
+ has_entries(multipart_chunk_size: 104857600),
512
+ )
513
+ @dummy.save
514
+ end
515
+ end
516
+ end
517
+
518
+ end
519
+
520
+ context "when using local storage" do
521
+ before do
522
+ Fog.unmock!
523
+ rebuild_model styles: { medium: "300x300>", thumb: "100x100>" },
524
+ storage: :fog,
525
+ url: '/:attachment/:filename',
526
+ fog_directory: "paperclip",
527
+ fog_credentials: { provider: :local, local_root: "." },
528
+ fog_host: 'localhost'
529
+
530
+ @file = File.new(fixture_file('5k.png'), 'rb')
531
+ @dummy = Dummy.new
532
+ @dummy.avatar = @file
533
+ @dummy.stubs(:new_record?).returns(false)
534
+ end
535
+
536
+ after do
537
+ @file.close
538
+ Fog.mock!
539
+ end
540
+
541
+ it "returns the public url in place of the expiring url" do
542
+ assert_match @dummy.avatar.public_url, @dummy.avatar.expiring_url
543
+ end
544
+ end
545
+ end