magic-paperclip 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
4
+ test/debug.log
5
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in paperclip-filemagic.gemspec
4
+ gemspec
@@ -0,0 +1,74 @@
1
+ # MagicPaperclip
2
+
3
+ [Paperclip] is a wonderful module by Thoughtbot that lets makes handling
4
+ attachments in Rails a breeze, except for one minor niggle - file types. It
5
+ relies on the content type header sent by the browser which is woefully
6
+ inconsistent. For example, when uploading a zip the possible values sent
7
+ for content type are:
8
+
9
+ + '`application/octet-stream`'
10
+ + '`application/x-zip-compressed`'
11
+ + '`application/zip`'
12
+ + '' (yes empty)
13
+
14
+ In short you can't rely on Content-Type from the browser to ever have a
15
+ sensible value.
16
+
17
+ Thus the purpose of this module: it uses the wonderful
18
+ [libmagic](http://www.darwinsys.com/file/) to work out the file type based
19
+ on the contents of the uploaded file without shelling out to `file` to do its
20
+ work.
21
+
22
+ # Requirements
23
+
24
+ The ruby-filemagic gem (which this gem uses) depends upon `libmagic` must be
25
+ installed to give us file type detection. On Linux this means installing the
26
+ relevant package:
27
+
28
+ sudo apt-get install libmagic-dev # Deb
29
+ sudo yum install file-devel # rpm
30
+ sudo emerge file # gentoo
31
+
32
+ On OSX ships with the `file` binary but not the `libmagic` shared library so I
33
+ recommend installing it via [homebrew]:
34
+
35
+ brew install libmagic
36
+ # Since this will be in a non-standard place we need to build ruby-filemagic specially
37
+ gem install ruby-filemagic -- --with-opt-dir=$(brew list libmagic | head -n1 | xargs dirname)
38
+
39
+ # Installation
40
+
41
+ Include the gem in your Gemfile:
42
+
43
+ gem 'magic-paperclip'
44
+
45
+ # Usage
46
+
47
+ Its all automatic - magic-paperclip does its trick by just being in the
48
+ Gemfile (via a Railtie).
49
+
50
+ When a Paperclip attachment is assigned to its content_type will be detected
51
+ and will overwrite what the browser sends.
52
+
53
+ # Caveats/Bugs
54
+
55
+ libmagic often returns charset info or similar for files (i.e. `text/plain;
56
+ charset=us-asci`) that this module attempts to remove to use just the base
57
+ type. Supposedly older versions of libmagic might return this in a
58
+ different format and thus not get removed. If you find an example of this
59
+ happening please let me know.
60
+
61
+ # Credits & License
62
+
63
+ ![digiresults](https://www.digiresults.com/stylesheets/images/logo_white.png)
64
+
65
+ This gem was developed for use at [DigiResults] and pulled out into a reusable gem.
66
+
67
+ Released under the [MIT License][MIT]
68
+
69
+ Copyright (c) 2011, Ash Berlin and DigiResults Ltd.
70
+
71
+ [Paperclip]: http://github.com/thoughtbot/paperclip
72
+ [homebrew]: http://mxcl.github.com/homebrew/
73
+ [MIT]: http://creativecommons.org/licenses/MIT/
74
+ [DigiResults]: http://www.digiresults.com/
@@ -0,0 +1,10 @@
1
+ require 'bundler'
2
+ require 'rake/testtask'
3
+
4
+ Bundler::GemHelper.install_tasks
5
+
6
+ task :default => :test
7
+ Rake::TestTask.new(:test) do |t|
8
+ t.libs << 'lib' << 'test'
9
+ t.pattern = 'test/**/*_test.rb'
10
+ end
@@ -0,0 +1,48 @@
1
+ # Released under MIT License
2
+ # Copyright (c) 2011 Ash Berlin and DigiResults Ltd.
3
+
4
+ require 'filemagic'
5
+ require 'paperclip'
6
+
7
+ require 'magic-paperclip/railtie'
8
+
9
+ module Paperclip
10
+ def self.magic_content_type!
11
+ Attachment.send :include, MagicPaperclip
12
+ end
13
+ end
14
+
15
+ module MagicPaperclip
16
+ def self.included( base )
17
+ base.class_eval do
18
+ alias_method :assign_without_filemagic, :assign
19
+ alias_method :assign, :assign_with_filemagic
20
+ end
21
+ end
22
+
23
+ def assign_with_filemagic( uploaded_file )
24
+ # Call next method up the chain
25
+ val = assign_without_filemagic( uploaded_file )
26
+
27
+ return val if uploaded_file.is_a?( Paperclip::Attachment )
28
+
29
+ if uploaded_file
30
+ magic = FileMagic.new( FileMagic::MAGIC_MIME )
31
+
32
+ if defined?( StringIO ) && uploaded_file.is_a?( StringIO )
33
+ type = magic.buffer( uploaded_file.string )
34
+ else
35
+ type = magic.file( uploaded_file.path )
36
+ end
37
+
38
+ # Remove the '; charset=us-ascii' from the end if there is one
39
+ type.sub! /\s*;.*$/, ''
40
+
41
+ instance_write( :content_type, type )
42
+ end
43
+ val
44
+ ensure
45
+ magic.close if magic
46
+ end
47
+
48
+ end
@@ -0,0 +1,12 @@
1
+ require 'magic-paperclip'
2
+
3
+ module MagicPaperclip
4
+ if defined? Rails::Railtie
5
+ require 'rails'
6
+ class Railtie < Rails::Railtie
7
+ initializer 'magic-paperclip' do
8
+ Paperclip.magic_content_type!
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ module MagicPaperclip
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "magic-paperclip/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "magic-paperclip"
7
+ s.version = MagicPaperclip::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Ash Berlin"]
10
+ s.email = ["ash.berlin@gmail.com"]
11
+ s.homepage = "https://github.com/DigiResults/magic-paperclip"
12
+ s.summary = %q{Filemagic based mimetype detection for Paperclip}
13
+ s.description = %q{Adds better (a.k.a magic) file type detection support into Thoughtbot's Paperclip}
14
+
15
+ #s.rubyforge_project = "paperclip-filemagic"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency 'ruby-filemagic'
23
+ s.add_dependency 'paperclip'
24
+
25
+ s.add_development_dependency 'mocha'
26
+ s.add_development_dependency 'shoulda'
27
+ s.add_development_dependency 'sqlite3-ruby'
28
+ end
@@ -0,0 +1,39 @@
1
+ require 'helper'
2
+
3
+ class ContentTypeTest < Test::Unit::TestCase
4
+ context "Assigning a StringIO attachment" do
5
+ setup do
6
+ rebuild_model
7
+ @file = StringIO.new("abc")
8
+ @file.stubs(:original_filename).returns("5k.png\n\n")
9
+ @file.stubs(:content_type).returns("image/png\n\n")
10
+ @file.stubs(:to_tempfile).returns(@file)
11
+ @dummy = Dummy.new
12
+ @dummy.avatar = @file
13
+ end
14
+
15
+ should "set content_type based on file magic" do
16
+ assert_equal "text/plain", @dummy.avatar.content_type
17
+ assert_equal "text/plain", @dummy.avatar_content_type
18
+ end
19
+ end
20
+
21
+ context "Assigning a ZIP upfile attachment" do
22
+ setup do
23
+ rebuild_model
24
+ @file = File.new File.join( FIXTURES_DIR, 'zip_file_called.txt' )
25
+ class << @file
26
+ include Paperclip::Upfile
27
+ end
28
+
29
+ @file.stubs(:content_type).returns("") # Some versions of chrome do this
30
+ @dummy = Dummy.new
31
+ @dummy.avatar = @file
32
+ end
33
+
34
+ should "set content_type based on file magic" do
35
+ assert_equal "application/zip", @dummy.avatar.content_type
36
+ assert_equal "application/zip", @dummy.avatar_content_type
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,3 @@
1
+ test:
2
+ adapter: sqlite3
3
+ database: ":memory:"
@@ -0,0 +1,42 @@
1
+ # Copied from Paperclip's own test suite
2
+
3
+ require 'active_record'
4
+ require 'mocha'
5
+ require 'shoulda'
6
+ require 'test/unit'
7
+
8
+ require 'magic-paperclip'
9
+
10
+ Paperclip.magic_content_type!
11
+
12
+ FIXTURES_DIR = File.join(File.dirname(__FILE__), "fixtures")
13
+ config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
14
+ ActiveRecord::Base.logger = ActiveSupport::BufferedLogger.new(File.dirname(__FILE__) + "/debug.log")
15
+ ActiveRecord::Base.establish_connection(config['test'])
16
+
17
+
18
+ class Dummy
19
+ end
20
+
21
+ def rebuild_model options = {}
22
+ ActiveRecord::Base.connection.create_table :dummies, :force => true do |table|
23
+ table.column :other, :string
24
+ table.column :avatar_file_name, :string
25
+ table.column :avatar_content_type, :string
26
+ table.column :avatar_file_size, :integer
27
+ table.column :avatar_updated_at, :datetime
28
+ table.column :avatar_fingerprint, :string
29
+ end
30
+ rebuild_class options
31
+ end
32
+
33
+ def rebuild_class options = {}
34
+ ActiveRecord::Base.send(:include, Paperclip::Glue)
35
+ Object.send(:remove_const, "Dummy") rescue nil
36
+ Object.const_set("Dummy", Class.new(ActiveRecord::Base))
37
+ Dummy.class_eval do
38
+ include Paperclip::Glue
39
+ has_attached_file :avatar, options
40
+ end
41
+ end
42
+
metadata ADDED
@@ -0,0 +1,125 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: magic-paperclip
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Ash Berlin
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-08-01 00:00:00 +01:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: ruby-filemagic
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: "0"
25
+ type: :runtime
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: paperclip
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: "0"
36
+ type: :runtime
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: mocha
40
+ prerelease: false
41
+ requirement: &id003 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ type: :development
48
+ version_requirements: *id003
49
+ - !ruby/object:Gem::Dependency
50
+ name: shoulda
51
+ prerelease: false
52
+ requirement: &id004 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ type: :development
59
+ version_requirements: *id004
60
+ - !ruby/object:Gem::Dependency
61
+ name: sqlite3-ruby
62
+ prerelease: false
63
+ requirement: &id005 !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: "0"
69
+ type: :development
70
+ version_requirements: *id005
71
+ description: Adds better (a.k.a magic) file type detection support into Thoughtbot's Paperclip
72
+ email:
73
+ - ash.berlin@gmail.com
74
+ executables: []
75
+
76
+ extensions: []
77
+
78
+ extra_rdoc_files: []
79
+
80
+ files:
81
+ - .gitignore
82
+ - Gemfile
83
+ - README.markdown
84
+ - Rakefile
85
+ - lib/magic-paperclip.rb
86
+ - lib/magic-paperclip/railtie.rb
87
+ - lib/magic-paperclip/version.rb
88
+ - magic-paperlcip.gemspec
89
+ - test/content_type_test.rb
90
+ - test/database.yml
91
+ - test/fixtures/zip_file_called.txt
92
+ - test/helper.rb
93
+ has_rdoc: true
94
+ homepage: https://github.com/DigiResults/magic-paperclip
95
+ licenses: []
96
+
97
+ post_install_message:
98
+ rdoc_options: []
99
+
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ none: false
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: "0"
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: "0"
114
+ requirements: []
115
+
116
+ rubyforge_project:
117
+ rubygems_version: 1.6.1
118
+ signing_key:
119
+ specification_version: 3
120
+ summary: Filemagic based mimetype detection for Paperclip
121
+ test_files:
122
+ - test/content_type_test.rb
123
+ - test/database.yml
124
+ - test/fixtures/zip_file_called.txt
125
+ - test/helper.rb