futuresinc-attachment_fu 1.0.4 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. data/VERSION.yml +1 -1
  2. data/attachment_fu.gemspec +11 -11
  3. data/init.rb +1 -1
  4. data/lib/attachment_fu/backends/cloud_file_backend.rb +209 -0
  5. data/lib/attachment_fu/backends/db_file_backend.rb +37 -0
  6. data/lib/attachment_fu/backends/file_system_backend.rb +124 -0
  7. data/lib/attachment_fu/backends/s3_backend.rb +392 -0
  8. data/lib/attachment_fu/processors/core_image_processor.rb +55 -0
  9. data/lib/attachment_fu/processors/gd2_processor.rb +53 -0
  10. data/lib/attachment_fu/processors/image_science_processor.rb +60 -0
  11. data/lib/attachment_fu/processors/mini_magick_processor.rb +131 -0
  12. data/lib/attachment_fu/processors/rmagick_processor.rb +56 -0
  13. data/lib/attachment_fu.rb +543 -0
  14. data/test/backends/remote/cloudfiles_test.rb +3 -3
  15. data/test/backends/remote/s3_test.rb +3 -3
  16. data/test/basic_test.rb +2 -2
  17. data/test/extra_attachment_test.rb +2 -2
  18. metadata +11 -11
  19. data/lib/technoweenie/attachment_fu/backends/cloud_file_backend.rb +0 -211
  20. data/lib/technoweenie/attachment_fu/backends/db_file_backend.rb +0 -39
  21. data/lib/technoweenie/attachment_fu/backends/file_system_backend.rb +0 -126
  22. data/lib/technoweenie/attachment_fu/backends/s3_backend.rb +0 -394
  23. data/lib/technoweenie/attachment_fu/processors/core_image_processor.rb +0 -59
  24. data/lib/technoweenie/attachment_fu/processors/gd2_processor.rb +0 -54
  25. data/lib/technoweenie/attachment_fu/processors/image_science_processor.rb +0 -61
  26. data/lib/technoweenie/attachment_fu/processors/mini_magick_processor.rb +0 -132
  27. data/lib/technoweenie/attachment_fu/processors/rmagick_processor.rb +0 -57
  28. data/lib/technoweenie/attachment_fu.rb +0 -545
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: futuresinc-attachment_fu
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Technoweenie
@@ -33,17 +33,17 @@ files:
33
33
  - attachment_fu.gemspec
34
34
  - init.rb
35
35
  - install.rb
36
+ - lib/attachment_fu.rb
37
+ - lib/attachment_fu/backends/cloud_file_backend.rb
38
+ - lib/attachment_fu/backends/db_file_backend.rb
39
+ - lib/attachment_fu/backends/file_system_backend.rb
40
+ - lib/attachment_fu/backends/s3_backend.rb
41
+ - lib/attachment_fu/processors/core_image_processor.rb
42
+ - lib/attachment_fu/processors/gd2_processor.rb
43
+ - lib/attachment_fu/processors/image_science_processor.rb
44
+ - lib/attachment_fu/processors/mini_magick_processor.rb
45
+ - lib/attachment_fu/processors/rmagick_processor.rb
36
46
  - lib/geometry.rb
37
- - lib/technoweenie/attachment_fu.rb
38
- - lib/technoweenie/attachment_fu/backends/cloud_file_backend.rb
39
- - lib/technoweenie/attachment_fu/backends/db_file_backend.rb
40
- - lib/technoweenie/attachment_fu/backends/file_system_backend.rb
41
- - lib/technoweenie/attachment_fu/backends/s3_backend.rb
42
- - lib/technoweenie/attachment_fu/processors/core_image_processor.rb
43
- - lib/technoweenie/attachment_fu/processors/gd2_processor.rb
44
- - lib/technoweenie/attachment_fu/processors/image_science_processor.rb
45
- - lib/technoweenie/attachment_fu/processors/mini_magick_processor.rb
46
- - lib/technoweenie/attachment_fu/processors/rmagick_processor.rb
47
47
  - rackspace_cloudfiles.yml.tpl
48
48
  - test/backends/db_file_test.rb
49
49
  - test/backends/file_system_test.rb
@@ -1,211 +0,0 @@
1
- module Technoweenie # :nodoc:
2
- module AttachmentFu # :nodoc:
3
- module Backends
4
- # = CloudFiles Storage Backend
5
- #
6
- # Enables use of {Rackspace Cloud Files}[http://www.mosso.com/cloudfiles.jsp] as a storage mechanism
7
- #
8
- # Based heavily on the Amazon S3 backend.
9
- #
10
- # == Requirements
11
- #
12
- # Requires the {Cloud Files Gem}[http://www.mosso.com/cloudfiles.jsp] by Rackspace
13
- #
14
- # == Configuration
15
- #
16
- # Configuration is done via <tt>RAILS_ROOT/config/rackspace_cloudfiles.yml</tt> and is loaded according to the <tt>RAILS_ENV</tt>.
17
- # The minimum connection options that you must specify are a container name, your Mosso login name and your Mosso API key.
18
- # You can sign up for Cloud Files and get access keys by visiting https://www.mosso.com/buy.htm
19
- #
20
- # Example configuration (RAILS_ROOT/config/rackspace_cloudfiles.yml)
21
- #
22
- # development:
23
- # container_name: appname_development
24
- # username: <your key>
25
- # api_key: <your key>
26
- #
27
- # test:
28
- # container_name: appname_test
29
- # username: <your key>
30
- # api_key: <your key>
31
- #
32
- # production:
33
- # container_name: appname
34
- # username: <your key>
35
- # apik_key: <your key>
36
- #
37
- # You can change the location of the config path by passing a full path to the :cloudfiles_config_path option.
38
- #
39
- # has_attachment :storage => :cloud_files, :cloudfiles_config_path => (RAILS_ROOT + '/config/mosso.yml')
40
- #
41
- # === Required configuration parameters
42
- #
43
- # * <tt>:username</tt> - The username for your Rackspace Cloud (Mosso) account. Provided by Rackspace.
44
- # * <tt>:secret_access_key</tt> - The api key for your Rackspace Cloud account. Provided by Rackspace.
45
- # * <tt>:container_name</tt> - The name of a container in your Cloud Files account.
46
- #
47
- # If any of these required arguments is missing, a AuthenticationException will be raised from CloudFiles::Connection.
48
- #
49
- # == Usage
50
- #
51
- # To specify Cloud Files as the storage mechanism for a model, set the acts_as_attachment <tt>:storage</tt> option to <tt>:cloud_files/tt>.
52
- #
53
- # class Photo < ActiveRecord::Base
54
- # has_attachment :storage => :cloud_files
55
- # end
56
- #
57
- # === Customizing the path
58
- #
59
- # By default, files are prefixed using a pseudo hierarchy in the form of <tt>:table_name/:id</tt>, which results
60
- # in Cloud Files object names (and urls) that look like: http://:server/:container_name/:table_name/:id/:filename with :table_name
61
- # representing the customizable portion of the path. You can customize this prefix using the <tt>:path_prefix</tt>
62
- # option:
63
- #
64
- # class Photo < ActiveRecord::Base
65
- # has_attachment :storage => :cloud_files, :path_prefix => 'my/custom/path'
66
- # end
67
- #
68
- # Which would result in public URLs like <tt>http(s)://:server/:container_name/my/custom/path/:id/:filename.</tt>
69
- #
70
- # === Permissions
71
- #
72
- # File permisisons are determined by the permissions of the container. At present, the options are public (and distributed
73
- # by the Limelight CDN), and private (only available to your login)
74
- #
75
- # === Other options
76
- #
77
- # Of course, all the usual configuration options apply, such as content_type and thumbnails:
78
- #
79
- # class Photo < ActiveRecord::Base
80
- # has_attachment :storage => :cloud_files, :content_type => ['application/pdf', :image], :resize_to => 'x50'
81
- # has_attachment :storage => :cloud_files, :thumbnails => { :thumb => [50, 50], :geometry => 'x50' }
82
- # end
83
- #
84
- # === Accessing Cloud Files URLs
85
- #
86
- # You can get an object's public URL using the cloudfiles_url accessor. For example, assuming that for your postcard app
87
- # you had a container name like 'postcard_world_development', and an attachment model called Photo:
88
- #
89
- # @postcard.cloudfiles_url # => http://cdn.cloudfiles.mosso.com/c45182/uploaded_files/20/london.jpg
90
- #
91
- # The resulting url is in the form: http://:server/:container_name/:table_name/:id/:file.
92
- # The optional thumbnail argument will output the thumbnail's filename (if any).
93
- #
94
- # Additionally, you can get an object's base path relative to the container root using
95
- # <tt>base_path</tt>:
96
- #
97
- # @photo.file_base_path # => uploaded_files/20
98
- #
99
- # And the full path (including the filename) using <tt>full_filename</tt>:
100
- #
101
- # @photo.full_filename # => uploaded_files/20/london.jpg
102
- #
103
- # Niether <tt>base_path</tt> or <tt>full_filename</tt> include the container name as part of the path.
104
- # You can retrieve the container name using the <tt>container_name</tt> method.
105
- module CloudFileBackend
106
- class RequiredLibraryNotFoundError < StandardError; end
107
- class ConfigFileNotFoundError < StandardError; end
108
-
109
- def self.included(base) #:nodoc:
110
- mattr_reader :container_name, :cloudfiles_config
111
-
112
- begin
113
- require 'cloudfiles'
114
- rescue LoadError
115
- raise RequiredLibraryNotFoundError.new('CloudFiles could not be loaded')
116
- end
117
-
118
- begin
119
- @@cloudfiles_config_path = base.attachment_options[:cloudfiles_config_path] || (RAILS_ROOT + '/config/rackspace_cloudfiles.yml')
120
- @@cloudfiles_config = @@cloudfiles_config = YAML.load(ERB.new(File.read(@@cloudfiles_config_path)).result)[RAILS_ENV].symbolize_keys
121
- rescue
122
- #raise ConfigFileNotFoundError.new('File %s not found' % @@cloudfiles_config_path)
123
- end
124
-
125
- @@container_name = @@cloudfiles_config[:container_name]
126
- @@cf = CloudFiles::Connection.new(@@cloudfiles_config[:username], @@cloudfiles_config[:api_key])
127
- @@container = @@cf.container(@@container_name)
128
-
129
- base.before_update :rename_file
130
- end
131
-
132
- # Overwrites the base filename writer in order to store the old filename
133
- def filename=(value)
134
- @old_filename = filename unless filename.nil? || @old_filename
135
- write_attribute :filename, sanitize_filename(value)
136
- end
137
-
138
- # The attachment ID used in the full path of a file
139
- def attachment_path_id
140
- ((respond_to?(:parent_id) && parent_id) || id).to_s
141
- end
142
-
143
- # The pseudo hierarchy containing the file relative to the container name
144
- # Example: <tt>:table_name/:id</tt>
145
- def base_path
146
- File.join(attachment_options[:path_prefix], attachment_path_id)
147
- end
148
-
149
- # The full path to the file relative to the container name
150
- # Example: <tt>:table_name/:id/:filename</tt>
151
- def full_filename(thumbnail = nil)
152
- File.join(base_path, thumbnail_name_for(thumbnail))
153
- end
154
-
155
- # All public objects are accessible via a GET request to the Cloud Files servers. You can generate a
156
- # url for an object using the cloudfiles_url method.
157
- #
158
- # @photo.cloudfiles_url
159
- #
160
- # The resulting url is in the CDN URL for the object
161
- #
162
- # The optional thumbnail argument will output the thumbnail's filename (if any).
163
- #
164
- # If you are trying to get the URL for a nonpublic container, nil will be returned.
165
- def cloudfiles_url(thumbnail = nil)
166
- if @@container.public?
167
- File.join(@@container.cdn_url, full_filename(thumbnail))
168
- else
169
- nil
170
- end
171
- end
172
- alias :public_filename :cloudfiles_url
173
-
174
- def create_temp_file
175
- write_to_temp_file current_data
176
- end
177
-
178
- def current_data
179
- @@container.get_object(full_filename).data
180
- end
181
-
182
- protected
183
- # Called in the after_destroy callback
184
- def destroy_file
185
- @@container.delete_object(full_filename)
186
- end
187
-
188
- def rename_file
189
- # Cloud Files doesn't rename right now, so we'll just nuke.
190
- return unless @old_filename && @old_filename != filename
191
-
192
- old_full_filename = File.join(base_path, @old_filename)
193
- @@container.delete_object(old_full_filename)
194
-
195
- @old_filename = nil
196
- true
197
- end
198
-
199
- def save_to_storage
200
- if save_attachment?
201
- @object = @@container.create_object(full_filename)
202
- @object.write((temp_path ? File.open(temp_path) : temp_data))
203
- end
204
-
205
- @old_filename = nil
206
- true
207
- end
208
- end
209
- end
210
- end
211
- end
@@ -1,39 +0,0 @@
1
- module Technoweenie # :nodoc:
2
- module AttachmentFu # :nodoc:
3
- module Backends
4
- # Methods for DB backed attachments
5
- module DbFileBackend
6
- def self.included(base) #:nodoc:
7
- Object.const_set(:DbFile, Class.new(ActiveRecord::Base)) unless Object.const_defined?(:DbFile)
8
- base.belongs_to :db_file, :class_name => '::DbFile', :foreign_key => 'db_file_id'
9
- end
10
-
11
- # Creates a temp file with the current db data.
12
- def create_temp_file
13
- write_to_temp_file current_data
14
- end
15
-
16
- # Gets the current data from the database
17
- def current_data
18
- db_file.data
19
- end
20
-
21
- protected
22
- # Destroys the file. Called in the after_destroy callback
23
- def destroy_file
24
- db_file.destroy if db_file
25
- end
26
-
27
- # Saves the data to the DbFile model
28
- def save_to_storage
29
- if save_attachment?
30
- (db_file || build_db_file).data = temp_data
31
- db_file.save!
32
- self.class.update_all ['db_file_id = ?', self.db_file_id = db_file.id], ['id = ?', id]
33
- end
34
- true
35
- end
36
- end
37
- end
38
- end
39
- end
@@ -1,126 +0,0 @@
1
- require 'fileutils'
2
- require 'digest/sha2'
3
-
4
- module Technoweenie # :nodoc:
5
- module AttachmentFu # :nodoc:
6
- module Backends
7
- # Methods for file system backed attachments
8
- module FileSystemBackend
9
- def self.included(base) #:nodoc:
10
- base.before_update :rename_file
11
- end
12
-
13
- # Gets the full path to the filename in this format:
14
- #
15
- # # This assumes a model name like MyModel
16
- # # public/#{table_name} is the default filesystem path
17
- # RAILS_ROOT/public/my_models/5/blah.jpg
18
- #
19
- # Overwrite this method in your model to customize the filename.
20
- # The optional thumbnail argument will output the thumbnail's filename.
21
- def full_filename(thumbnail = nil)
22
- file_system_path = (thumbnail ? thumbnail_class : self).attachment_options[:path_prefix].to_s
23
- File.join(RAILS_ROOT, file_system_path, *partitioned_path(thumbnail_name_for(thumbnail)))
24
- end
25
-
26
- # Used as the base path that #public_filename strips off full_filename to create the public path
27
- def base_path
28
- @base_path ||= File.join(RAILS_ROOT, 'public')
29
- end
30
-
31
- # The attachment ID used in the full path of a file
32
- def attachment_path_id
33
- ((respond_to?(:parent_id) && parent_id) || id) || 0
34
- end
35
-
36
- # Partitions the given path into an array of path components.
37
- #
38
- # For example, given an <tt>*args</tt> of ["foo", "bar"], it will return
39
- # <tt>["0000", "0001", "foo", "bar"]</tt> (assuming that that id returns 1).
40
- #
41
- # If the id is not an integer, then path partitioning will be performed by
42
- # hashing the string value of the id with SHA-512, and splitting the result
43
- # into 4 components. If the id a 128-bit UUID (as set by :uuid_primary_key => true)
44
- # then it will be split into 2 components.
45
- #
46
- # To turn this off entirely, set :partition => false.
47
- def partitioned_path(*args)
48
- if respond_to?(:attachment_options) && attachment_options[:partition] == false
49
- args
50
- elsif attachment_options[:uuid_primary_key]
51
- # Primary key is a 128-bit UUID in hex format. Split it into 2 components.
52
- path_id = attachment_path_id.to_s
53
- component1 = path_id[0..15] || "-"
54
- component2 = path_id[16..-1] || "-"
55
- [component1, component2] + args
56
- else
57
- path_id = attachment_path_id
58
- if path_id.is_a?(Integer)
59
- # Primary key is an integer. Split it after padding it with 0.
60
- ("%08d" % path_id).scan(/..../) + args
61
- else
62
- # Primary key is a String. Hash it, then split it into 4 components.
63
- hash = Digest::SHA512.hexdigest(path_id.to_s)
64
- [hash[0..31], hash[32..63], hash[64..95], hash[96..127]] + args
65
- end
66
- end
67
- end
68
-
69
- # Gets the public path to the file
70
- # The optional thumbnail argument will output the thumbnail's filename.
71
- def public_filename(thumbnail = nil)
72
- full_filename(thumbnail).gsub %r(^#{Regexp.escape(base_path)}), ''
73
- end
74
-
75
- def filename=(value)
76
- @old_filename = full_filename unless filename.nil? || @old_filename
77
- write_attribute :filename, sanitize_filename(value)
78
- end
79
-
80
- # Creates a temp file from the currently saved file.
81
- def create_temp_file
82
- copy_to_temp_file full_filename
83
- end
84
-
85
- protected
86
- # Destroys the file. Called in the after_destroy callback
87
- def destroy_file
88
- FileUtils.rm full_filename
89
- # remove directory also if it is now empty
90
- Dir.rmdir(File.dirname(full_filename)) if (Dir.entries(File.dirname(full_filename))-['.','..']).empty?
91
- rescue
92
- logger.info "Exception destroying #{full_filename.inspect}: [#{$!.class.name}] #{$1.to_s}"
93
- logger.warn $!.backtrace.collect { |b| " > #{b}" }.join("\n")
94
- end
95
-
96
- # Renames the given file before saving
97
- def rename_file
98
- return unless @old_filename && @old_filename != full_filename
99
- if save_attachment? && File.exists?(@old_filename)
100
- FileUtils.rm @old_filename
101
- elsif File.exists?(@old_filename)
102
- FileUtils.mv @old_filename, full_filename
103
- end
104
- @old_filename = nil
105
- true
106
- end
107
-
108
- # Saves the file to the file system
109
- def save_to_storage
110
- if save_attachment?
111
- # TODO: This overwrites the file if it exists, maybe have an allow_overwrite option?
112
- FileUtils.mkdir_p(File.dirname(full_filename))
113
- FileUtils.cp(temp_path, full_filename)
114
- FileUtils.chmod(attachment_options[:chmod] || 0644, full_filename)
115
- end
116
- @old_filename = nil
117
- true
118
- end
119
-
120
- def current_data
121
- File.file?(full_filename) ? File.read(full_filename) : nil
122
- end
123
- end
124
- end
125
- end
126
- end