plowdawg-carrierwave 0.5.8

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