miloops-attachment_fu 3.2.5

Sign up to get free protection for your applications and to get access to all the features.
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