carrierwave 0.5.2 → 0.5.3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of carrierwave might be problematic. Click here for more details.
- data/README.rdoc +104 -72
- data/lib/carrierwave.rb +7 -2
- data/lib/carrierwave/compatibility/paperclip.rb +11 -11
- data/lib/carrierwave/orm/activerecord.rb +10 -3
- data/lib/carrierwave/processing/image_science.rb +6 -0
- data/lib/carrierwave/processing/mini_magick.rb +1 -0
- data/lib/carrierwave/processing/rmagick.rb +1 -0
- data/lib/carrierwave/sanitized_file.rb +1 -1
- data/lib/carrierwave/storage/cloud_files.rb +20 -4
- data/lib/carrierwave/storage/fog.rb +317 -0
- data/lib/carrierwave/storage/s3.rb +10 -6
- data/lib/carrierwave/uploader/cache.rb +15 -1
- data/lib/carrierwave/uploader/configuration.rb +52 -28
- data/lib/carrierwave/uploader/download.rb +15 -4
- data/lib/carrierwave/uploader/url.rb +3 -2
- data/lib/carrierwave/uploader/versions.rb +4 -6
- data/lib/carrierwave/version.rb +1 -1
- metadata +112 -66
@@ -0,0 +1,317 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'fog'
|
5
|
+
rescue LoadError
|
6
|
+
raise "You don't have the 'fog' gem installed"
|
7
|
+
end
|
8
|
+
|
9
|
+
module CarrierWave
|
10
|
+
module Storage
|
11
|
+
|
12
|
+
##
|
13
|
+
# Stores things using the "fog" gem.
|
14
|
+
#
|
15
|
+
# fog supports storing files with AWS, Google, Local and Rackspace
|
16
|
+
#
|
17
|
+
# You need to setup some options to configure your usage:
|
18
|
+
#
|
19
|
+
# [:fog_credentials] credentials for service
|
20
|
+
# [:fog_directory] specifies name of directory to store data in
|
21
|
+
#
|
22
|
+
# [:fog_attributes] (optional) additional attributes to set on files
|
23
|
+
# [:fog_host] (optional) non-default host to serve files from
|
24
|
+
# [:fog_public] (optional) public readability, defaults to true
|
25
|
+
# [:fog_authenticated_url_expiration] (optional) time (in seconds) that authenticated urls
|
26
|
+
# will be valid, when fog_public is false and provider is AWS or Google, defaults to 600
|
27
|
+
#
|
28
|
+
#
|
29
|
+
# AWS credentials contain the following keys:
|
30
|
+
#
|
31
|
+
# [:aws_access_key_id]
|
32
|
+
# [:aws_secret_access_key]
|
33
|
+
# [:region] (optional) defaults to 'us-east-1'
|
34
|
+
# :region should be one of ['eu-west-1', 'us-east-1', 'ap-southeast-1', 'us-west-1', 'ap-northeast-1']
|
35
|
+
#
|
36
|
+
#
|
37
|
+
# Google credentials contain the following keys:
|
38
|
+
# [:google_storage_access_key_id]
|
39
|
+
# [:google_storage_secrete_access_key]
|
40
|
+
#
|
41
|
+
#
|
42
|
+
# Local credentials contain the following keys:
|
43
|
+
#
|
44
|
+
# [:local_root] local path to files
|
45
|
+
#
|
46
|
+
#
|
47
|
+
# Rackspace credentials contain the following keys:
|
48
|
+
#
|
49
|
+
# [:rackspace_username]
|
50
|
+
# [:rackspace_api_key]
|
51
|
+
#
|
52
|
+
#
|
53
|
+
# A full example with AWS credentials:
|
54
|
+
# CarrierWave.configure do |config|
|
55
|
+
# config.fog_credentials = {
|
56
|
+
# :aws_access_key_id => 'xxxxxx',
|
57
|
+
# :aws_secret_access_key => 'yyyyyy',
|
58
|
+
# :provider => 'AWS'
|
59
|
+
# }
|
60
|
+
# config.fog_directory = 'directoryname'
|
61
|
+
# config.fog_public = true
|
62
|
+
# end
|
63
|
+
#
|
64
|
+
class Fog < Abstract
|
65
|
+
|
66
|
+
##
|
67
|
+
# Store a file
|
68
|
+
#
|
69
|
+
# === Parameters
|
70
|
+
#
|
71
|
+
# [file (CarrierWave::SanitizedFile)] the file to store
|
72
|
+
#
|
73
|
+
# === Returns
|
74
|
+
#
|
75
|
+
# [CarrierWave::Storage::Fog::File] the stored file
|
76
|
+
#
|
77
|
+
def store!(file)
|
78
|
+
f = CarrierWave::Storage::Fog::File.new(uploader, self, uploader.store_path)
|
79
|
+
f.store(file)
|
80
|
+
f
|
81
|
+
end
|
82
|
+
|
83
|
+
##
|
84
|
+
# Retrieve a file
|
85
|
+
#
|
86
|
+
# === Parameters
|
87
|
+
#
|
88
|
+
# [identifier (String)] unique identifier for file
|
89
|
+
#
|
90
|
+
# === Returns
|
91
|
+
#
|
92
|
+
# [CarrierWave::Storage::Fog::File] the stored file
|
93
|
+
#
|
94
|
+
def retrieve!(identifier)
|
95
|
+
CarrierWave::Storage::Fog::File.new(uploader, self, uploader.store_path(identifier))
|
96
|
+
end
|
97
|
+
|
98
|
+
def connection
|
99
|
+
@connection ||= begin
|
100
|
+
::Fog::Storage.new(uploader.fog_credentials)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
class File
|
105
|
+
|
106
|
+
##
|
107
|
+
# Current local path to file
|
108
|
+
#
|
109
|
+
# === Returns
|
110
|
+
#
|
111
|
+
# [String] a path to file
|
112
|
+
#
|
113
|
+
attr_reader :path
|
114
|
+
|
115
|
+
##
|
116
|
+
# Return all attributes from file
|
117
|
+
#
|
118
|
+
# === Returns
|
119
|
+
#
|
120
|
+
# [Hash] attributes from file
|
121
|
+
#
|
122
|
+
def attributes
|
123
|
+
file.attributes
|
124
|
+
end
|
125
|
+
|
126
|
+
##
|
127
|
+
# Return a temporary authenticated url to a private file, if available
|
128
|
+
# Only supported for AWS and Google providers
|
129
|
+
#
|
130
|
+
# === Returns
|
131
|
+
#
|
132
|
+
# [String] temporary authenticated url
|
133
|
+
# or
|
134
|
+
# [NilClass] no authenticated url available
|
135
|
+
#
|
136
|
+
def authenticated_url
|
137
|
+
if ['AWS', 'Google'].include?(@uploader.fog_credentials[:provider])
|
138
|
+
# avoid a get by using local references
|
139
|
+
local_directory = connection.directories.new(:key => @uploader.fog_directory)
|
140
|
+
local_file = local_directory.files.new(:key => path)
|
141
|
+
local_file.url(::Fog::Time.now + @uploader.fog_authenticated_url_expiration)
|
142
|
+
else
|
143
|
+
nil
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
##
|
148
|
+
# Lookup value for file content-type header
|
149
|
+
#
|
150
|
+
# === Returns
|
151
|
+
#
|
152
|
+
# [String] value of content-type
|
153
|
+
#
|
154
|
+
def content_type
|
155
|
+
@content_type || file.content_type
|
156
|
+
end
|
157
|
+
|
158
|
+
##
|
159
|
+
# Set non-default content-type header (default is file.content_type)
|
160
|
+
#
|
161
|
+
# === Returns
|
162
|
+
#
|
163
|
+
# [String] returns new content type value
|
164
|
+
#
|
165
|
+
def content_type=(new_content_type)
|
166
|
+
@content_type = new_content_type
|
167
|
+
end
|
168
|
+
|
169
|
+
##
|
170
|
+
# Remove the file from service
|
171
|
+
#
|
172
|
+
# === Returns
|
173
|
+
#
|
174
|
+
# [Boolean] true for success or raises error
|
175
|
+
#
|
176
|
+
def delete
|
177
|
+
file.destroy
|
178
|
+
end
|
179
|
+
|
180
|
+
##
|
181
|
+
# deprecated: All attributes from file (includes headers)
|
182
|
+
#
|
183
|
+
# === Returns
|
184
|
+
#
|
185
|
+
# [Hash] attributes from file
|
186
|
+
#
|
187
|
+
def headers
|
188
|
+
location = caller.first
|
189
|
+
warning = "[yellow][WARN] headers is deprecated, use attributes instead[/]"
|
190
|
+
warning << " [light_black](#{location})[/]"
|
191
|
+
Formatador.display_line(warning)
|
192
|
+
attributes
|
193
|
+
end
|
194
|
+
|
195
|
+
def initialize(uploader, base, path)
|
196
|
+
@uploader, @base, @path = uploader, base, path
|
197
|
+
end
|
198
|
+
|
199
|
+
##
|
200
|
+
# Read content of file from service
|
201
|
+
#
|
202
|
+
# === Returns
|
203
|
+
#
|
204
|
+
# [String] contents of file
|
205
|
+
def read
|
206
|
+
file.body
|
207
|
+
end
|
208
|
+
|
209
|
+
##
|
210
|
+
# Return size of file body
|
211
|
+
#
|
212
|
+
# === Returns
|
213
|
+
#
|
214
|
+
# [Integer] size of file body
|
215
|
+
#
|
216
|
+
def size
|
217
|
+
file.content_length
|
218
|
+
end
|
219
|
+
|
220
|
+
##
|
221
|
+
# Write file to service
|
222
|
+
#
|
223
|
+
# === Returns
|
224
|
+
#
|
225
|
+
# [Boolean] true on success or raises error
|
226
|
+
def store(new_file)
|
227
|
+
@content_type ||= new_file.content_type
|
228
|
+
@file = directory.files.create({
|
229
|
+
:body => new_file.read,
|
230
|
+
:content_type => @content_type,
|
231
|
+
:key => path,
|
232
|
+
:public => @uploader.fog_public
|
233
|
+
}.merge(@uploader.fog_attributes))
|
234
|
+
true
|
235
|
+
end
|
236
|
+
|
237
|
+
##
|
238
|
+
# Return a url to a public file, if available
|
239
|
+
#
|
240
|
+
# === Returns
|
241
|
+
#
|
242
|
+
# [String] public url
|
243
|
+
# or
|
244
|
+
# [NilClass] no public url available
|
245
|
+
#
|
246
|
+
def public_url
|
247
|
+
if host = @uploader.fog_host
|
248
|
+
"#{host}/#{path}"
|
249
|
+
else
|
250
|
+
# avoid a get by just using local reference
|
251
|
+
directory.files.new(:key => path).public_url
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
##
|
256
|
+
# Return url to file, if avaliable
|
257
|
+
#
|
258
|
+
# === Returns
|
259
|
+
#
|
260
|
+
# [String] url
|
261
|
+
# or
|
262
|
+
# [NilClass] no url available
|
263
|
+
#
|
264
|
+
def url
|
265
|
+
if !@uploader.fog_public
|
266
|
+
authenticated_url
|
267
|
+
else
|
268
|
+
public_url
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
private
|
273
|
+
|
274
|
+
##
|
275
|
+
# connection to service
|
276
|
+
#
|
277
|
+
# === Returns
|
278
|
+
#
|
279
|
+
# [Fog::#{provider}::Storage] connection to service
|
280
|
+
#
|
281
|
+
def connection
|
282
|
+
@base.connection
|
283
|
+
end
|
284
|
+
|
285
|
+
##
|
286
|
+
# lookup directory containing file
|
287
|
+
#
|
288
|
+
# === Returns
|
289
|
+
#
|
290
|
+
# [Fog::#{provider}::Directory] containing directory
|
291
|
+
#
|
292
|
+
def directory
|
293
|
+
@directory ||= begin
|
294
|
+
connection.directories.get(@uploader.fog_directory) || connection.directories.create(
|
295
|
+
:key => @uploader.fog_directory,
|
296
|
+
:public => @uploader.fog_public
|
297
|
+
)
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
##
|
302
|
+
# lookup file
|
303
|
+
#
|
304
|
+
# === Returns
|
305
|
+
#
|
306
|
+
# [Fog::#{provider}::File] file data from remote service
|
307
|
+
#
|
308
|
+
def file
|
309
|
+
@file ||= directory.files.get(path)
|
310
|
+
end
|
311
|
+
|
312
|
+
end
|
313
|
+
|
314
|
+
end # Fog
|
315
|
+
|
316
|
+
end # Storage
|
317
|
+
end # CarrierWave
|
@@ -132,7 +132,7 @@ module CarrierWave
|
|
132
132
|
end
|
133
133
|
|
134
134
|
def authenticated_url
|
135
|
-
connection.get_object_url(bucket, path, Time.now +
|
135
|
+
connection.get_object_url(bucket, path, Time.now + authentication_timeout)
|
136
136
|
end
|
137
137
|
|
138
138
|
def store(file)
|
@@ -184,6 +184,10 @@ module CarrierWave
|
|
184
184
|
@uploader.s3_bucket
|
185
185
|
end
|
186
186
|
|
187
|
+
def authentication_timeout
|
188
|
+
@uploader.s3_authentication_timeout
|
189
|
+
end
|
190
|
+
|
187
191
|
def connection
|
188
192
|
@base.connection
|
189
193
|
end
|
@@ -222,11 +226,11 @@ module CarrierWave
|
|
222
226
|
end
|
223
227
|
|
224
228
|
def connection
|
225
|
-
@connection ||= Fog::Storage.new(
|
226
|
-
:
|
227
|
-
:
|
228
|
-
:
|
229
|
-
:region
|
229
|
+
@connection ||= ::Fog::Storage.new(
|
230
|
+
:aws_access_key_id => uploader.s3_access_key_id,
|
231
|
+
:aws_secret_access_key => uploader.s3_secret_access_key,
|
232
|
+
:provider => 'AWS',
|
233
|
+
:region => uploader.s3_region
|
230
234
|
)
|
231
235
|
end
|
232
236
|
|
@@ -63,6 +63,19 @@ module CarrierWave
|
|
63
63
|
@cache_id
|
64
64
|
end
|
65
65
|
|
66
|
+
##
|
67
|
+
# Caches the remotely stored file
|
68
|
+
#
|
69
|
+
# This is useful when about to process images. Most processing solutions
|
70
|
+
# require the file to be stored on the local filesystem.
|
71
|
+
#
|
72
|
+
def cache_stored_file!
|
73
|
+
sanitized = SanitizedFile.new :tempfile => StringIO.new(file.read),
|
74
|
+
:filename => File.basename(path), :content_type => file.content_type
|
75
|
+
|
76
|
+
cache! sanitized
|
77
|
+
end
|
78
|
+
|
66
79
|
##
|
67
80
|
# Returns a String which uniquely identifies the currently cached file for later retrieval
|
68
81
|
#
|
@@ -87,9 +100,10 @@ module CarrierWave
|
|
87
100
|
#
|
88
101
|
def cache!(new_file)
|
89
102
|
new_file = CarrierWave::SanitizedFile.new(new_file)
|
90
|
-
raise CarrierWave::FormNotMultipart if new_file.is_path? && ensure_multipart_form
|
91
103
|
|
92
104
|
unless new_file.empty?
|
105
|
+
raise CarrierWave::FormNotMultipart if new_file.is_path? && ensure_multipart_form
|
106
|
+
|
93
107
|
with_callbacks(:cache, new_file) do
|
94
108
|
self.cache_id = CarrierWave.generate_cache_id unless cache_id
|
95
109
|
|
@@ -16,10 +16,13 @@ module CarrierWave
|
|
16
16
|
add_config :s3_headers
|
17
17
|
add_config :s3_region
|
18
18
|
add_config :s3_use_ssl
|
19
|
+
add_config :s3_authentication_timeout
|
19
20
|
add_config :cloud_files_username
|
20
21
|
add_config :cloud_files_api_key
|
21
22
|
add_config :cloud_files_container
|
22
23
|
add_config :cloud_files_cdn_host
|
24
|
+
add_config :cloud_files_auth_url
|
25
|
+
add_config :cloud_files_snet
|
23
26
|
add_config :grid_fs_connection
|
24
27
|
add_config :grid_fs_database
|
25
28
|
add_config :grid_fs_host
|
@@ -33,6 +36,14 @@ module CarrierWave
|
|
33
36
|
add_config :ensure_multipart_form
|
34
37
|
add_config :delete_tmp_file_after_storage
|
35
38
|
|
39
|
+
# fog
|
40
|
+
add_config :fog_attributes
|
41
|
+
add_config :fog_credentials
|
42
|
+
add_config :fog_directory
|
43
|
+
add_config :fog_host
|
44
|
+
add_config :fog_public
|
45
|
+
add_config :fog_authenticated_url_expiration
|
46
|
+
|
36
47
|
# Mounting
|
37
48
|
add_config :ignore_integrity_errors
|
38
49
|
add_config :ignore_processing_errors
|
@@ -40,34 +51,8 @@ module CarrierWave
|
|
40
51
|
add_config :validate_processing
|
41
52
|
add_config :mount_on
|
42
53
|
|
43
|
-
|
44
|
-
|
45
|
-
config.storage_engines = {
|
46
|
-
:file => "CarrierWave::Storage::File",
|
47
|
-
:s3 => "CarrierWave::Storage::S3",
|
48
|
-
:grid_fs => "CarrierWave::Storage::GridFS",
|
49
|
-
:right_s3 => "CarrierWave::Storage::RightS3",
|
50
|
-
:cloud_files => "CarrierWave::Storage::CloudFiles"
|
51
|
-
}
|
52
|
-
config.storage = :file
|
53
|
-
config.s3_headers = {}
|
54
|
-
config.s3_access_policy = :public_read
|
55
|
-
config.s3_region = 'us-east-1'
|
56
|
-
config.s3_use_ssl = false
|
57
|
-
config.grid_fs_database = 'carrierwave'
|
58
|
-
config.grid_fs_host = 'localhost'
|
59
|
-
config.grid_fs_port = 27017
|
60
|
-
config.store_dir = 'uploads'
|
61
|
-
config.cache_dir = 'uploads/tmp'
|
62
|
-
config.delete_tmp_file_after_storage = true
|
63
|
-
config.ignore_integrity_errors = true
|
64
|
-
config.ignore_processing_errors = true
|
65
|
-
config.validate_integrity = true
|
66
|
-
config.validate_processing = true
|
67
|
-
config.root = CarrierWave.root
|
68
|
-
config.enable_processing = true
|
69
|
-
config.ensure_multipart_form = true
|
70
|
-
end
|
54
|
+
# set default values
|
55
|
+
reset_config
|
71
56
|
end
|
72
57
|
|
73
58
|
module ClassMethods
|
@@ -132,6 +117,45 @@ module CarrierWave
|
|
132
117
|
def configure
|
133
118
|
yield self
|
134
119
|
end
|
120
|
+
|
121
|
+
##
|
122
|
+
# sets configuration back to default
|
123
|
+
#
|
124
|
+
def reset_config
|
125
|
+
configure do |config|
|
126
|
+
config.permissions = 0644
|
127
|
+
config.storage_engines = {
|
128
|
+
:file => "CarrierWave::Storage::File",
|
129
|
+
:fog => "CarrierWave::Storage::Fog",
|
130
|
+
:s3 => "CarrierWave::Storage::S3",
|
131
|
+
:grid_fs => "CarrierWave::Storage::GridFS",
|
132
|
+
:right_s3 => "CarrierWave::Storage::RightS3",
|
133
|
+
:cloud_files => "CarrierWave::Storage::CloudFiles"
|
134
|
+
}
|
135
|
+
config.storage = :file
|
136
|
+
config.s3_headers = {}
|
137
|
+
config.s3_access_policy = :public_read
|
138
|
+
config.s3_region = 'us-east-1'
|
139
|
+
config.s3_authentication_timeout = 600
|
140
|
+
config.grid_fs_database = 'carrierwave'
|
141
|
+
config.grid_fs_host = 'localhost'
|
142
|
+
config.grid_fs_port = 27017
|
143
|
+
config.fog_attributes = {}
|
144
|
+
config.fog_credentials = {}
|
145
|
+
config.fog_public = true
|
146
|
+
config.fog_authenticated_url_expiration = 600
|
147
|
+
config.store_dir = 'uploads'
|
148
|
+
config.cache_dir = 'uploads/tmp'
|
149
|
+
config.delete_tmp_file_after_storage = true
|
150
|
+
config.ignore_integrity_errors = true
|
151
|
+
config.ignore_processing_errors = true
|
152
|
+
config.validate_integrity = true
|
153
|
+
config.validate_processing = true
|
154
|
+
config.root = CarrierWave.root
|
155
|
+
config.enable_processing = true
|
156
|
+
config.ensure_multipart_form = true
|
157
|
+
end
|
158
|
+
end
|
135
159
|
end
|
136
160
|
|
137
161
|
end
|