plowdawg-carrierwave 0.5.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. data/README.md +674 -0
  2. data/lib/carrierwave.rb +109 -0
  3. data/lib/carrierwave/compatibility/paperclip.rb +95 -0
  4. data/lib/carrierwave/locale/en.yml +5 -0
  5. data/lib/carrierwave/mount.rb +382 -0
  6. data/lib/carrierwave/orm/activerecord.rb +46 -0
  7. data/lib/carrierwave/processing/mime_types.rb +58 -0
  8. data/lib/carrierwave/processing/mini_magick.rb +253 -0
  9. data/lib/carrierwave/processing/rmagick.rb +279 -0
  10. data/lib/carrierwave/sanitized_file.rb +302 -0
  11. data/lib/carrierwave/storage/abstract.rb +30 -0
  12. data/lib/carrierwave/storage/cloud_files.rb +188 -0
  13. data/lib/carrierwave/storage/file.rb +47 -0
  14. data/lib/carrierwave/storage/fog.rb +332 -0
  15. data/lib/carrierwave/storage/right_s3.rb +1 -0
  16. data/lib/carrierwave/storage/s3.rb +240 -0
  17. data/lib/carrierwave/test/matchers.rb +164 -0
  18. data/lib/carrierwave/uploader.rb +44 -0
  19. data/lib/carrierwave/uploader/cache.rb +160 -0
  20. data/lib/carrierwave/uploader/callbacks.rb +35 -0
  21. data/lib/carrierwave/uploader/configuration.rb +162 -0
  22. data/lib/carrierwave/uploader/default_url.rb +19 -0
  23. data/lib/carrierwave/uploader/download.rb +75 -0
  24. data/lib/carrierwave/uploader/extension_whitelist.rb +49 -0
  25. data/lib/carrierwave/uploader/mountable.rb +39 -0
  26. data/lib/carrierwave/uploader/processing.rb +90 -0
  27. data/lib/carrierwave/uploader/proxy.rb +77 -0
  28. data/lib/carrierwave/uploader/remove.rb +23 -0
  29. data/lib/carrierwave/uploader/store.rb +113 -0
  30. data/lib/carrierwave/uploader/url.rb +45 -0
  31. data/lib/carrierwave/uploader/versions.rb +237 -0
  32. data/lib/carrierwave/validations/active_model.rb +79 -0
  33. data/lib/carrierwave/version.rb +3 -0
  34. data/lib/generators/templates/uploader.rb +49 -0
  35. data/lib/generators/uploader_generator.rb +7 -0
  36. metadata +215 -0
@@ -0,0 +1,302 @@
1
+ # encoding: utf-8
2
+
3
+ require 'pathname'
4
+ require 'active_support/core_ext/string/multibyte'
5
+
6
+ module CarrierWave
7
+
8
+ ##
9
+ # SanitizedFile is a base class which provides a common API around all
10
+ # the different quirky Ruby File libraries. It has support for Tempfile,
11
+ # File, StringIO, Merb-style upload Hashes, as well as paths given as
12
+ # Strings and Pathnames.
13
+ #
14
+ # It's probably needlessly comprehensive and complex. Help is appreciated.
15
+ #
16
+ class SanitizedFile
17
+
18
+ attr_accessor :file
19
+
20
+ class << self
21
+ attr_writer :sanitize_regexp
22
+
23
+ def sanitize_regexp
24
+ @sanitize_regexp ||= /[^a-zA-Z0-9\.\-\+_]/
25
+ end
26
+ end
27
+
28
+ def initialize(file)
29
+ self.file = file
30
+ end
31
+
32
+ ##
33
+ # Returns the filename as is, without sanizting it.
34
+ #
35
+ # === Returns
36
+ #
37
+ # [String] the unsanitized filename
38
+ #
39
+ def original_filename
40
+ return @original_filename if @original_filename
41
+ if @file and @file.respond_to?(:original_filename)
42
+ @file.original_filename
43
+ elsif path
44
+ File.basename(path)
45
+ end
46
+ end
47
+
48
+ ##
49
+ # Returns the filename, sanitized to strip out any evil characters.
50
+ #
51
+ # === Returns
52
+ #
53
+ # [String] the sanitized filename
54
+ #
55
+ def filename
56
+ sanitize(original_filename) if original_filename
57
+ end
58
+
59
+ alias_method :identifier, :filename
60
+
61
+ ##
62
+ # Returns the part of the filename before the extension. So if a file is called 'test.jpeg'
63
+ # this would return 'test'
64
+ #
65
+ # === Returns
66
+ #
67
+ # [String] the first part of the filename
68
+ #
69
+ def basename
70
+ split_extension(filename)[0] if filename
71
+ end
72
+
73
+ ##
74
+ # Returns the file extension
75
+ #
76
+ # === Returns
77
+ #
78
+ # [String] the extension
79
+ #
80
+ def extension
81
+ split_extension(filename)[1] if filename
82
+ end
83
+
84
+ ##
85
+ # Returns the file's size.
86
+ #
87
+ # === Returns
88
+ #
89
+ # [Integer] the file's size in bytes.
90
+ #
91
+ def size
92
+ if is_path?
93
+ exists? ? File.size(path) : 0
94
+ elsif @file.respond_to?(:size)
95
+ @file.size
96
+ elsif path
97
+ exists? ? File.size(path) : 0
98
+ else
99
+ 0
100
+ end
101
+ end
102
+
103
+ ##
104
+ # Returns the full path to the file. If the file has no path, it will return nil.
105
+ #
106
+ # === Returns
107
+ #
108
+ # [String, nil] the path where the file is located.
109
+ #
110
+ def path
111
+ unless @file.blank?
112
+ if is_path?
113
+ File.expand_path(@file)
114
+ elsif @file.respond_to?(:path) and not @file.path.blank?
115
+ File.expand_path(@file.path)
116
+ end
117
+ end
118
+ end
119
+
120
+ ##
121
+ # === Returns
122
+ #
123
+ # [Boolean] whether the file is supplied as a pathname or string.
124
+ #
125
+ def is_path?
126
+ !!((@file.is_a?(String) || @file.is_a?(Pathname)) && !@file.blank?)
127
+ end
128
+
129
+ ##
130
+ # === Returns
131
+ #
132
+ # [Boolean] whether the file is valid and has a non-zero size
133
+ #
134
+ def empty?
135
+ @file.nil? || self.size.nil? || self.size.zero?
136
+ end
137
+
138
+ ##
139
+ # === Returns
140
+ #
141
+ # [Boolean] Whether the file exists
142
+ #
143
+ def exists?
144
+ return File.exists?(self.path) if self.path
145
+ return false
146
+ end
147
+
148
+ ##
149
+ # Returns the contents of the file.
150
+ #
151
+ # === Returns
152
+ #
153
+ # [String] contents of the file
154
+ #
155
+ def read
156
+ if is_path?
157
+ File.open(@file, "rb") {|file| file.read}
158
+ else
159
+ @file.rewind if @file.respond_to?(:rewind)
160
+ @file.read
161
+ end
162
+ end
163
+
164
+ ##
165
+ # Moves the file to the given path
166
+ #
167
+ # === Parameters
168
+ #
169
+ # [new_path (String)] The path where the file should be moved.
170
+ # [permissions (Integer)] permissions to set on the file in its new location.
171
+ #
172
+ def move_to(new_path, permissions=nil)
173
+ return if self.empty?
174
+ new_path = File.expand_path(new_path)
175
+
176
+ mkdir!(new_path)
177
+ if exists?
178
+ FileUtils.mv(path, new_path) unless new_path == path
179
+ else
180
+ File.open(new_path, "wb") { |f| f.write(read) }
181
+ end
182
+ chmod!(new_path, permissions)
183
+ self.file = new_path
184
+ end
185
+
186
+ ##
187
+ # Creates a copy of this file and moves it to the given path. Returns the copy.
188
+ #
189
+ # === Parameters
190
+ #
191
+ # [new_path (String)] The path where the file should be copied to.
192
+ # [permissions (Integer)] permissions to set on the copy
193
+ #
194
+ # === Returns
195
+ #
196
+ # @return [CarrierWave::SanitizedFile] the location where the file will be stored.
197
+ #
198
+ def copy_to(new_path, permissions=nil)
199
+ return if self.empty?
200
+ new_path = File.expand_path(new_path)
201
+
202
+ mkdir!(new_path)
203
+ if exists?
204
+ FileUtils.cp(path, new_path) unless new_path == path
205
+ else
206
+ File.open(new_path, "wb") { |f| f.write(read) }
207
+ end
208
+ chmod!(new_path, permissions)
209
+ self.class.new({:tempfile => new_path, :content_type => content_type})
210
+ end
211
+
212
+ ##
213
+ # Removes the file from the filesystem.
214
+ #
215
+ def delete
216
+ FileUtils.rm(self.path) if exists?
217
+ end
218
+
219
+ ##
220
+ # Returns the content type of the file.
221
+ #
222
+ # === Returns
223
+ #
224
+ # [String] the content type of the file
225
+ #
226
+ def content_type
227
+ return @content_type if @content_type
228
+ @file.content_type.chomp if @file.respond_to?(:content_type) and @file.content_type
229
+ end
230
+
231
+ ##
232
+ # Sets the content type of the file.
233
+ #
234
+ # === Returns
235
+ #
236
+ # [String] the content type of the file
237
+ #
238
+ def content_type=(type)
239
+ @content_type = type
240
+ end
241
+
242
+ ##
243
+ # Used to sanitize the file name. Public to allow overriding for non-latin characters.
244
+ #
245
+ # === Returns
246
+ #
247
+ # [Regexp] the regexp for sanitizing the file name
248
+ #
249
+ def sanitize_regexp
250
+ CarrierWave::SanitizedFile.sanitize_regexp
251
+ end
252
+
253
+ private
254
+
255
+ def file=(file)
256
+ if file.is_a?(Hash)
257
+ @file = file["tempfile"] || file[:tempfile]
258
+ @original_filename = file["filename"] || file[:filename]
259
+ @content_type = file["content_type"] || file[:content_type]
260
+ else
261
+ @file = file
262
+ @original_filename = nil
263
+ @content_type = nil
264
+ end
265
+ end
266
+
267
+ # create the directory if it doesn't exist
268
+ def mkdir!(path)
269
+ FileUtils.mkdir_p(File.dirname(path)) unless File.exists?(File.dirname(path))
270
+ end
271
+
272
+ def chmod!(path, permissions)
273
+ File.chmod(permissions, path) if permissions
274
+ end
275
+
276
+ # Sanitize the filename, to prevent hacking
277
+ def sanitize(name)
278
+ name = name.gsub("\\", "/") # work-around for IE
279
+ name = File.basename(name)
280
+ name = name.gsub(sanitize_regexp,"_")
281
+ name = "_#{name}" if name =~ /\A\.+\z/
282
+ name = "unnamed" if name.size == 0
283
+ return name.mb_chars.to_s
284
+ end
285
+
286
+ def split_extension(filename)
287
+ # regular expressions to try for identifying extensions
288
+ extension_matchers = [
289
+ /\A(.+)\.(tar\.gz)\z/, # matches "something.tar.gz"
290
+ /\A(.+)\.([^\.]+)\z/ # matches "something.jpg"
291
+ ]
292
+
293
+ extension_matchers.each do |regexp|
294
+ if filename =~ regexp
295
+ return $1, $2
296
+ end
297
+ end
298
+ return filename, "" # In case we weren't able to split the extension
299
+ end
300
+
301
+ end # SanitizedFile
302
+ end # CarrierWave
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+
3
+ module CarrierWave
4
+ module Storage
5
+
6
+ ##
7
+ # This file serves mostly as a specification for Storage engines. There is no requirement
8
+ # that storage engines must be a subclass of this class.
9
+ #
10
+ class Abstract
11
+
12
+ attr_reader :uploader
13
+
14
+ def initialize(uploader)
15
+ @uploader = uploader
16
+ end
17
+
18
+ def identifier
19
+ uploader.filename
20
+ end
21
+
22
+ def store!(file)
23
+ end
24
+
25
+ def retrieve!(identifier)
26
+ end
27
+
28
+ end # Abstract
29
+ end # Storage
30
+ end # CarrierWave
@@ -0,0 +1,188 @@
1
+ # encoding: utf-8
2
+ require 'cloudfiles'
3
+
4
+ module CarrierWave
5
+ module Storage
6
+
7
+ ##
8
+ # Uploads things to Rackspace Cloud Files webservices using the Rackspace libraries (cloudfiles gem).
9
+ # In order for CarrierWave to connect to Cloud Files, you'll need to specify an username, api key
10
+ # and container. Optional arguments are config.cloud_files_snet (using the private internal
11
+ # Rackspace network for communication) and config.cloud_files_auth_url (for connecting to Rackspace's
12
+ # UK infrastructure or an OpenStack Swift installation)
13
+ #
14
+ # CarrierWave.configure do |config|
15
+ # config.cloud_files_username = "xxxxxx"
16
+ # config.cloud_files_api_key = "xxxxxx"
17
+ # config.cloud_files_container = "my_container"
18
+ # config.cloud_files_auth_url = "https://lon.auth.api.rackspacecloud.com/v1.0"
19
+ # config.cloud_files_snet = true
20
+ # end
21
+ #
22
+ # You can optionally include your CDN host name in the configuration.
23
+ # This is *highly* recommended, as without it every request requires a lookup
24
+ # of this information.
25
+ #
26
+ # config.cloud_files_cdn_host = "c000000.cdn.rackspacecloud.com"
27
+ #
28
+ #
29
+ class CloudFiles < Abstract
30
+
31
+ class File
32
+
33
+ def initialize(uploader, base, path)
34
+ @uploader = uploader
35
+ @path = path
36
+ @base = base
37
+ end
38
+
39
+ ##
40
+ # Returns the current path/filename of the file on Cloud Files.
41
+ #
42
+ # === Returns
43
+ #
44
+ # [String] A path
45
+ #
46
+ def path
47
+ @path
48
+ end
49
+
50
+ ##
51
+ # Reads the contents of the file from Cloud Files
52
+ #
53
+ # === Returns
54
+ #
55
+ # [String] contents of the file
56
+ #
57
+ def read
58
+ object = cf_container.object(@path)
59
+ @content_type = object.content_type
60
+ object.data
61
+ end
62
+
63
+ ##
64
+ # Remove the file from Cloud Files
65
+ #
66
+ def delete
67
+ begin
68
+ cf_container.delete_object(@path)
69
+ rescue ::CloudFiles::Exception::NoSuchObject
70
+ # If the file's not there, don't panic
71
+ nil
72
+ end
73
+ end
74
+
75
+ ##
76
+ # Returns the url on the Cloud Files CDN. Note that the parent container must be marked as
77
+ # public for this to work.
78
+ #
79
+ # === Returns
80
+ #
81
+ # [String] file's url
82
+ #
83
+ def url
84
+ if @uploader.cloud_files_cdn_host
85
+ "http://" + @uploader.cloud_files_cdn_host + "/" + @path
86
+ else
87
+ begin
88
+ cf_container.object(@path).public_url
89
+ rescue ::CloudFiles::Exception::NoSuchObject
90
+ nil
91
+ end
92
+ end
93
+ end
94
+
95
+ def content_type
96
+ cf_container.object(@path).content_type
97
+ end
98
+
99
+ def content_type=(new_content_type)
100
+ headers["content-type"] = new_content_type
101
+ end
102
+
103
+ ##
104
+ # Writes the supplied data into the object on Cloud Files.
105
+ #
106
+ # === Returns
107
+ #
108
+ # boolean
109
+ #
110
+ def store(data,headers={})
111
+ object = cf_container.create_object(@path)
112
+ object.write(data,headers)
113
+ end
114
+
115
+ private
116
+
117
+ def headers
118
+ @headers ||= { }
119
+ end
120
+
121
+ def container
122
+ @uploader.cloud_files_container
123
+ end
124
+
125
+ def connection
126
+ @base.connection
127
+ end
128
+
129
+ def cf_connection
130
+ config = {:username => @uploader.cloud_files_username, :api_key => @uploader.cloud_files_api_key}
131
+ config[:auth_url] = @uploader.cloud_files_auth_url if @uploader.respond_to?(:cloud_files_auth_url)
132
+ config[:snet] = @uploader.cloud_files_snet if @uploader.respond_to?(:cloud_files_snet)
133
+ @cf_connection ||= ::CloudFiles::Connection.new(config)
134
+ end
135
+
136
+ def cf_container
137
+ if @cf_container
138
+ @cf_container
139
+ else
140
+ begin
141
+ @cf_container = cf_connection.container(container)
142
+ rescue NoSuchContainerException
143
+ @cf_container = cf_connection.create_container(container)
144
+ @cf_container.make_public
145
+ end
146
+ @cf_container
147
+ end
148
+ end
149
+
150
+
151
+ end
152
+
153
+ ##
154
+ # Store the file on Cloud Files
155
+ #
156
+ # === Parameters
157
+ #
158
+ # [file (CarrierWave::SanitizedFile)] the file to store
159
+ #
160
+ # === Returns
161
+ #
162
+ # [CarrierWave::Storage::CloudFiles::File] the stored file
163
+ #
164
+ def store!(file)
165
+ cloud_files_options = {'Content-Type' => file.content_type}
166
+ f = CarrierWave::Storage::CloudFiles::File.new(uploader, self, uploader.store_path)
167
+ f.store(file.read,cloud_files_options)
168
+ f
169
+ end
170
+
171
+ # Do something to retrieve the file
172
+ #
173
+ # @param [String] identifier uniquely identifies the file
174
+ #
175
+ # [identifier (String)] uniquely identifies the file
176
+ #
177
+ # === Returns
178
+ #
179
+ # [CarrierWave::Storage::CloudFiles::File] the stored file
180
+ #
181
+ def retrieve!(identifier)
182
+ CarrierWave::Storage::CloudFiles::File.new(uploader, self, uploader.store_path(identifier))
183
+ end
184
+
185
+
186
+ end # CloudFiles
187
+ end # Storage
188
+ end # CarrierWave