miloops-attachment_fu 3.2.5

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 (49) hide show
  1. data/CHANGELOG +63 -0
  2. data/LICENSE +20 -0
  3. data/README +253 -0
  4. data/Rakefile +22 -0
  5. data/amazon_s3.yml.tpl +17 -0
  6. data/install.rb +7 -0
  7. data/lib/geometry.rb +96 -0
  8. data/lib/pothoven-attachment_fu.rb +23 -0
  9. data/lib/technoweenie/attachment_fu.rb +578 -0
  10. data/lib/technoweenie/attachment_fu/backends/cloud_file_backend.rb +211 -0
  11. data/lib/technoweenie/attachment_fu/backends/db_file_backend.rb +39 -0
  12. data/lib/technoweenie/attachment_fu/backends/file_system_backend.rb +126 -0
  13. data/lib/technoweenie/attachment_fu/backends/s3_backend.rb +394 -0
  14. data/lib/technoweenie/attachment_fu/processors/core_image_processor.rb +66 -0
  15. data/lib/technoweenie/attachment_fu/processors/gd2_processor.rb +59 -0
  16. data/lib/technoweenie/attachment_fu/processors/image_science_processor.rb +80 -0
  17. data/lib/technoweenie/attachment_fu/processors/mini_magick_processor.rb +142 -0
  18. data/lib/technoweenie/attachment_fu/processors/rmagick_processor.rb +66 -0
  19. data/rackspace_cloudfiles.yml.tpl +14 -0
  20. data/test/backends/db_file_test.rb +16 -0
  21. data/test/backends/file_system_test.rb +143 -0
  22. data/test/backends/remote/cloudfiles_test.rb +102 -0
  23. data/test/backends/remote/s3_test.rb +119 -0
  24. data/test/base_attachment_tests.rb +77 -0
  25. data/test/basic_test.rb +120 -0
  26. data/test/database.yml +18 -0
  27. data/test/extra_attachment_test.rb +67 -0
  28. data/test/fixtures/attachment.rb +304 -0
  29. data/test/fixtures/files/fake/rails.png +0 -0
  30. data/test/fixtures/files/foo.txt +1 -0
  31. data/test/fixtures/files/rails.jpg +0 -0
  32. data/test/fixtures/files/rails.png +0 -0
  33. data/test/geometry_test.rb +114 -0
  34. data/test/processors/core_image_test.rb +58 -0
  35. data/test/processors/gd2_test.rb +51 -0
  36. data/test/processors/image_science_test.rb +54 -0
  37. data/test/processors/mini_magick_test.rb +122 -0
  38. data/test/processors/rmagick_test.rb +272 -0
  39. data/test/schema.rb +136 -0
  40. data/test/test_helper.rb +180 -0
  41. data/test/validation_test.rb +55 -0
  42. data/vendor/red_artisan/core_image/filters/color.rb +27 -0
  43. data/vendor/red_artisan/core_image/filters/effects.rb +31 -0
  44. data/vendor/red_artisan/core_image/filters/perspective.rb +25 -0
  45. data/vendor/red_artisan/core_image/filters/quality.rb +25 -0
  46. data/vendor/red_artisan/core_image/filters/scale.rb +47 -0
  47. data/vendor/red_artisan/core_image/filters/watermark.rb +32 -0
  48. data/vendor/red_artisan/core_image/processor.rb +123 -0
  49. metadata +98 -0
data/test/schema.rb ADDED
@@ -0,0 +1,136 @@
1
+ ActiveRecord::Schema.define(:version => 0) do
2
+ create_table :attachments, :force => true do |t|
3
+ t.column :db_file_id, :integer
4
+ t.column :parent_id, :integer
5
+ t.column :imageable_id, :integer
6
+ t.column :imageable_type, :string, :limit => 255
7
+ t.column :thumbnail, :string
8
+ t.column :filename, :string, :limit => 255
9
+ t.column :content_type, :string, :limit => 255
10
+ t.column :size, :integer
11
+ t.column :width, :integer
12
+ t.column :height, :integer
13
+ t.column :aspect_ratio, :float
14
+ end
15
+
16
+ create_table :file_attachments, :force => true do |t|
17
+ t.column :parent_id, :integer
18
+ t.column :thumbnail, :string
19
+ t.column :filename, :string, :limit => 255
20
+ t.column :content_type, :string, :limit => 255
21
+ t.column :size, :integer
22
+ t.column :width, :integer
23
+ t.column :height, :integer
24
+ t.column :type, :string
25
+ t.column :aspect_ratio, :float
26
+ end
27
+
28
+ create_table :file_attachments_with_string_id, :id => false, :force => true do |t|
29
+ t.column :id, :string
30
+ t.column :parent_id, :string
31
+ t.column :thumbnail, :string
32
+ t.column :filename, :string, :limit => 255
33
+ t.column :content_type, :string, :limit => 255
34
+ t.column :size, :integer
35
+ t.column :width, :integer
36
+ t.column :height, :integer
37
+ t.column :type, :string
38
+ t.column :aspect_ratio, :float
39
+ end
40
+
41
+ create_table :gd2_attachments, :force => true do |t|
42
+ t.column :parent_id, :integer
43
+ t.column :thumbnail, :string
44
+ t.column :filename, :string, :limit => 255
45
+ t.column :content_type, :string, :limit => 255
46
+ t.column :size, :integer
47
+ t.column :width, :integer
48
+ t.column :height, :integer
49
+ t.column :type, :string
50
+ end
51
+
52
+ create_table :image_science_attachments, :force => true do |t|
53
+ t.column :parent_id, :integer
54
+ t.column :thumbnail, :string
55
+ t.column :filename, :string, :limit => 255
56
+ t.column :content_type, :string, :limit => 255
57
+ t.column :size, :integer
58
+ t.column :width, :integer
59
+ t.column :height, :integer
60
+ t.column :type, :string
61
+ end
62
+
63
+ create_table :core_image_attachments, :force => true do |t|
64
+ t.column :parent_id, :integer
65
+ t.column :thumbnail, :string
66
+ t.column :filename, :string, :limit => 255
67
+ t.column :content_type, :string, :limit => 255
68
+ t.column :size, :integer
69
+ t.column :width, :integer
70
+ t.column :height, :integer
71
+ t.column :type, :string
72
+ end
73
+
74
+ create_table :mini_magick_attachments, :force => true do |t|
75
+ t.column :parent_id, :integer
76
+ t.column :thumbnail, :string
77
+ t.column :filename, :string, :limit => 255
78
+ t.column :content_type, :string, :limit => 255
79
+ t.column :size, :integer
80
+ t.column :width, :integer
81
+ t.column :height, :integer
82
+ t.column :type, :string
83
+ end
84
+
85
+ create_table :mini_magick_attachments, :force => true do |t|
86
+ t.column :parent_id, :integer
87
+ t.column :thumbnail, :string
88
+ t.column :filename, :string, :limit => 255
89
+ t.column :content_type, :string, :limit => 255
90
+ t.column :size, :integer
91
+ t.column :width, :integer
92
+ t.column :height, :integer
93
+ t.column :type, :string
94
+ end
95
+
96
+ create_table :orphan_attachments, :force => true do |t|
97
+ t.column :db_file_id, :integer
98
+ t.column :filename, :string, :limit => 255
99
+ t.column :content_type, :string, :limit => 255
100
+ t.column :size, :integer
101
+ end
102
+
103
+ create_table :minimal_attachments, :force => true do |t|
104
+ t.column :size, :integer
105
+ t.column :content_type, :string, :limit => 255
106
+ end
107
+
108
+ create_table :db_files, :force => true do |t|
109
+ t.column :data, :binary
110
+ end
111
+
112
+ create_table :s3_attachments, :force => true do |t|
113
+ t.column :parent_id, :integer
114
+ t.column :thumbnail, :string
115
+ t.column :filename, :string, :limit => 255
116
+ t.column :content_type, :string, :limit => 255
117
+ t.column :size, :integer
118
+ t.column :width, :integer
119
+ t.column :height, :integer
120
+ t.column :type, :string
121
+ t.column :aspect_ratio, :float
122
+ end
123
+
124
+ create_table :cloud_files_attachments, :force => true do |t|
125
+ t.column :parent_id, :integer
126
+ t.column :thumbnail, :string
127
+ t.column :filename, :string, :limit => 255
128
+ t.column :content_type, :string, :limit => 255
129
+ t.column :size, :integer
130
+ t.column :width, :integer
131
+ t.column :height, :integer
132
+ t.column :type, :string
133
+ t.column :aspect_ratio, :float
134
+ end
135
+
136
+ end
@@ -0,0 +1,180 @@
1
+
2
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
3
+
4
+ ENV['RAILS_ENV'] = 'test'
5
+ ENV['RAILS_ROOT'] ||= File.dirname(__FILE__) + '/../../../..'
6
+
7
+ require 'test/unit'
8
+ require File.expand_path(File.join(ENV['RAILS_ROOT'], 'config/environment.rb'))
9
+
10
+ config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
11
+ ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
12
+
13
+ db_adapter = ENV['DB']
14
+
15
+ # no db passed, try one of these fine config-free DBs before bombing.
16
+ db_adapter ||=
17
+ begin
18
+ require 'rubygems'
19
+ require 'sqlite'
20
+ 'sqlite'
21
+ rescue MissingSourceFile
22
+ begin
23
+ require 'sqlite3'
24
+ 'sqlite3'
25
+ rescue MissingSourceFile
26
+ end
27
+ end
28
+
29
+ if db_adapter.nil?
30
+ raise "No DB Adapter selected. Pass the DB= option to pick one, or install Sqlite or Sqlite3."
31
+ end
32
+
33
+ ActiveRecord::Base.establish_connection(config[db_adapter])
34
+
35
+ load(File.dirname(__FILE__) + "/schema.rb")
36
+
37
+ FIXTURE_PATH = File.dirname(__FILE__) + "/fixtures"
38
+ $LOAD_PATH.unshift(FIXTURE_PATH)
39
+
40
+ class Test::Unit::TestCase #:nodoc:
41
+ include ActionDispatch::TestProcess
42
+ def create_fixtures(*table_names)
43
+ if block_given?
44
+ Fixtures.create_fixtures(FIXTURE_PATH, table_names) { yield }
45
+ else
46
+ Fixtures.create_fixtures(FIXTURE_PATH, table_names)
47
+ end
48
+ end
49
+
50
+ def setup
51
+ Attachment.saves = 0
52
+ DbFile.transaction { [Attachment, FileAttachment, OrphanAttachment, MinimalAttachment, DbFile].each { |klass| klass.delete_all } }
53
+ attachment_model self.class.attachment_model
54
+ end
55
+
56
+ def teardown
57
+ FileUtils.rm_rf File.join(File.dirname(__FILE__), 'files')
58
+ # Files generated by random_tempfile_filename
59
+ FileUtils.rm_rf Dir['[0-9]*.{png,jpg}']
60
+ end
61
+
62
+ #self.use_transactional_fixtures = true
63
+ #self.use_instantiated_fixtures = false
64
+
65
+ def self.attachment_model(klass = nil)
66
+ @attachment_model = klass if klass
67
+ @attachment_model
68
+ end
69
+
70
+ def self.test_against_class(test_method, klass, subclass = false)
71
+ define_method("#{test_method}_on_#{:sub if subclass}class") do
72
+ klass = Class.new(klass) if subclass
73
+ attachment_model klass
74
+ send test_method, klass
75
+ end
76
+ end
77
+
78
+ def self.test_against_subclass(test_method, klass)
79
+ test_against_class test_method, klass, true
80
+ end
81
+
82
+ protected
83
+ def upload_file(options = {})
84
+ use_temp_file options[:filename] do |file|
85
+ opts = { :uploaded_data => fixture_file_upload(file, options[:content_type] || 'image/png') }
86
+ opts.update(options.reject { |k, v| ![:imageable_type, :imageable_id].include?(k) })
87
+ att = attachment_model.create opts
88
+ att.reload unless att.new_record?
89
+ return att
90
+ end
91
+ end
92
+
93
+ def upload_merb_file(options = {})
94
+ use_temp_file options[:filename] do |file|
95
+ att = attachment_model.create :uploaded_data => {"size" => file.size, "content_type" => options[:content_type] || 'image/png', "filename" => file, 'tempfile' => fixture_file_upload(file, options[:content_type] || 'image/png')}
96
+ att.reload unless att.new_record?
97
+ return att
98
+ end
99
+ end
100
+
101
+ def use_temp_file(fixture_filename)
102
+ temp_path = File.join('/tmp', File.basename(fixture_filename))
103
+ temp_dir = File.join(FIXTURE_PATH, 'tmp')
104
+ use_file = File.join(FIXTURE_PATH, temp_path)
105
+ FileUtils.mkdir_p temp_dir
106
+ FileUtils.cp File.join(FIXTURE_PATH, fixture_filename), use_file
107
+ yield use_file
108
+ ensure
109
+ FileUtils.rm_rf temp_dir
110
+ end
111
+
112
+ def assert_created(num = 1)
113
+ assert_difference attachment_model.base_class, :count, num do
114
+ if attachment_model.included_modules.include? DbFile
115
+ assert_difference DbFile, :count, num do
116
+ yield
117
+ end
118
+ else
119
+ yield
120
+ end
121
+ end
122
+ end
123
+
124
+ def assert_valid(record)
125
+ assert record.valid?, record.errors.full_messages.join("\n")
126
+ end
127
+
128
+ def assert_file_jpeg_quality(model, thumbnail, expected)
129
+ filename = if model.respond_to?(:full_filename)
130
+ model.full_filename(thumbnail)
131
+ else
132
+ thumb = thumbnail ? model.thumbnails.find(:first, :conditions => { :thumbnail => thumbnail.to_s }, :include => :db_file) : model
133
+ unless thumb && thumb.db_file && thumb.db_file.data && thumb.db_file.data.size > 0
134
+ STDERR.puts "Cannot find DB file data for thumbnail #{thumbnail.inspect} -> Aborting JPEG quality check."
135
+ return
136
+ end
137
+ result = Tempfile.new('dbfile_dump').path
138
+ File.open(result, 'wb') { |f| f.write(thumb.db_file.data) }
139
+ result
140
+ end
141
+ quality = %x(identify -format '%Q' "#{filename}" 2> /dev/null)
142
+ if $?.success?
143
+ assert_equal expected, quality.to_i, "Produced JPEG quality (thumbnail: #{thumbnail.inspect}) is incorrect."
144
+ else
145
+ STDERR.puts "ImageMagick's identify not found / not in PATH: can't quickly check produced image quality."
146
+ end
147
+ end
148
+
149
+ def assert_not_created
150
+ assert_created(0) { yield }
151
+ end
152
+
153
+ def should_reject_by_size_with(klass)
154
+ attachment_model klass
155
+ assert_not_created do
156
+ attachment = upload_file :filename => '/files/rails.png'
157
+ assert attachment.new_record?
158
+ assert attachment.errors.on(:size)
159
+ assert_nil attachment.db_file if attachment.respond_to?(:db_file)
160
+ end
161
+ end
162
+
163
+ def assert_difference(object, method = nil, difference = 1)
164
+ initial_value = object.send(method)
165
+ yield
166
+ assert_equal initial_value + difference, object.send(method)
167
+ end
168
+
169
+ def assert_no_difference(object, method, &block)
170
+ assert_difference object, method, 0, &block
171
+ end
172
+
173
+ def attachment_model(klass = nil)
174
+ @attachment_model = klass if klass
175
+ @attachment_model
176
+ end
177
+ end
178
+
179
+ require File.join(File.dirname(__FILE__), 'fixtures/attachment')
180
+ require File.join(File.dirname(__FILE__), 'base_attachment_tests')
@@ -0,0 +1,55 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
2
+
3
+ class ValidationTest < Test::Unit::TestCase
4
+ def test_should_invalidate_big_files
5
+ @attachment = SmallAttachment.new
6
+ assert !@attachment.valid?
7
+ assert @attachment.errors[:size]
8
+
9
+ @attachment.size = 2000
10
+ assert !@attachment.valid?
11
+ assert @attachment.errors[:size], @attachment.errors.full_messages.to_sentence
12
+
13
+ @attachment.size = 1000
14
+ assert !@attachment.valid?
15
+ assert @attachment.errors[:size].empty?
16
+ end
17
+
18
+ def test_should_invalidate_small_files
19
+ @attachment = BigAttachment.new
20
+ assert !@attachment.valid?
21
+ assert @attachment.errors[:size]
22
+
23
+ @attachment.size = 2000
24
+ assert !@attachment.valid?
25
+ assert @attachment.errors[:size], @attachment.errors.full_messages.to_sentence
26
+
27
+ @attachment.size = 1.megabyte
28
+ assert !@attachment.valid?
29
+ assert @attachment.errors[:size].empty?
30
+ end
31
+
32
+ def test_should_validate_content_type
33
+ @attachment = PdfAttachment.new
34
+ assert !@attachment.valid?
35
+ assert @attachment.errors[:content_type]
36
+
37
+ @attachment.content_type = 'foo'
38
+ assert !@attachment.valid?
39
+ assert @attachment.errors[:content_type]
40
+
41
+ @attachment.content_type = 'pdf'
42
+ assert !@attachment.valid?
43
+ assert @attachment.errors[:content_type].empty?
44
+ end
45
+
46
+ def test_should_require_filename
47
+ @attachment = Attachment.new
48
+ assert !@attachment.valid?
49
+ assert @attachment.errors[:filename]
50
+
51
+ @attachment.filename = 'foo'
52
+ assert !@attachment.valid?
53
+ assert @attachment.errors[:filename].empty?
54
+ end
55
+ end
@@ -0,0 +1,27 @@
1
+ module RedArtisan
2
+ module CoreImage
3
+ module Filters
4
+ module Color
5
+
6
+ def greyscale(color = nil, intensity = 1.00)
7
+ create_core_image_context(@original.extent.size.width, @original.extent.size.height)
8
+
9
+ color = OSX::CIColor.colorWithString("1.0 1.0 1.0 1.0") unless color
10
+
11
+ @original.color_monochrome :inputColor => color, :inputIntensity => intensity do |greyscale|
12
+ @target = greyscale
13
+ end
14
+ end
15
+
16
+ def sepia(intensity = 1.00)
17
+ create_core_image_context(@original.extent.size.width, @original.extent.size.height)
18
+
19
+ @original.sepia_tone :inputIntensity => intensity do |sepia|
20
+ @target = sepia
21
+ end
22
+ end
23
+
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,31 @@
1
+ module RedArtisan
2
+ module CoreImage
3
+ module Filters
4
+ module Effects
5
+
6
+ def spotlight(position, points_at, brightness, concentration, color)
7
+ create_core_image_context(@original.extent.size.width, @original.extent.size.height)
8
+
9
+ @original.spot_light :inputLightPosition => vector3(*position), :inputLightPointsAt => vector3(*points_at),
10
+ :inputBrightness => brightness, :inputConcentration => concentration, :inputColor => color do |spot|
11
+ @target = spot
12
+ end
13
+ end
14
+
15
+ def edges(intensity = 1.00)
16
+ create_core_image_context(@original.extent.size.width, @original.extent.size.height)
17
+
18
+ @original.edges :inputIntensity => intensity do |edged|
19
+ @target = edged
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def vector3(x, y, w)
26
+ OSX::CIVector.vectorWithX_Y_Z(x, y, w)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,25 @@
1
+ module RedArtisan
2
+ module CoreImage
3
+ module Filters
4
+ module Perspective
5
+
6
+ def perspective(top_left, top_right, bottom_left, bottom_right)
7
+ create_core_image_context(@original.extent.size.width, @original.extent.size.height)
8
+
9
+ @original.perspective_transform :inputTopLeft => top_left, :inputTopRight => top_right, :inputBottomLeft => bottom_left, :inputBottomRight => bottom_right do |transformed|
10
+ @target = transformed
11
+ end
12
+ end
13
+
14
+ def perspective_tiled(top_left, top_right, bottom_left, bottom_right)
15
+ create_core_image_context(@original.extent.size.width, @original.extent.size.height)
16
+
17
+ @original.perspective_tile :inputTopLeft => top_left, :inputTopRight => top_right, :inputBottomLeft => bottom_left, :inputBottomRight => bottom_right do |tiled|
18
+ @target = tiled
19
+ end
20
+ end
21
+
22
+ end
23
+ end
24
+ end
25
+ end