paperclip 5.2.1 → 6.1.0
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.
- checksums.yaml +5 -5
- data/.github/issue_template.md +3 -0
- data/MIGRATING-ES.md +317 -0
- data/MIGRATING.md +375 -0
- data/NEWS +36 -0
- data/README.md +52 -18
- data/UPGRADING +3 -3
- data/features/step_definitions/attachment_steps.rb +10 -10
- data/features/step_definitions/rails_steps.rb +1 -1
- data/lib/generators/paperclip/paperclip_generator.rb +9 -1
- data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +1 -1
- data/lib/paperclip/attachment.rb +19 -6
- data/lib/paperclip/file_command_content_type_detector.rb +1 -1
- data/lib/paperclip/filename_cleaner.rb +0 -1
- data/lib/paperclip/geometry_detector_factory.rb +3 -3
- data/lib/paperclip/helpers.rb +3 -3
- data/lib/paperclip/interpolations.rb +6 -1
- data/lib/paperclip/io_adapters/abstract_adapter.rb +11 -6
- data/lib/paperclip/io_adapters/attachment_adapter.rb +7 -1
- data/lib/paperclip/io_adapters/http_url_proxy_adapter.rb +2 -1
- data/lib/paperclip/io_adapters/uri_adapter.rb +8 -6
- data/lib/paperclip/logger.rb +1 -1
- data/lib/paperclip/media_type_spoof_detector.rb +11 -7
- data/lib/paperclip/processor.rb +10 -2
- data/lib/paperclip/schema.rb +1 -1
- data/lib/paperclip/storage/fog.rb +3 -2
- data/lib/paperclip/storage/s3.rb +8 -16
- data/lib/paperclip/style.rb +0 -1
- data/lib/paperclip/thumbnail.rb +8 -5
- data/lib/paperclip/url_generator.rb +1 -0
- data/lib/paperclip/validators/media_type_spoof_detection_validator.rb +4 -0
- data/lib/paperclip/version.rb +1 -1
- data/lib/paperclip.rb +2 -1
- data/paperclip.gemspec +2 -2
- data/spec/paperclip/attachment_processing_spec.rb +0 -1
- data/spec/paperclip/attachment_spec.rb +17 -2
- data/spec/paperclip/content_type_detector_spec.rb +1 -1
- data/spec/paperclip/file_command_content_type_detector_spec.rb +15 -1
- data/spec/paperclip/filename_cleaner_spec.rb +0 -1
- data/spec/paperclip/integration_spec.rb +41 -5
- data/spec/paperclip/interpolations_spec.rb +9 -0
- data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +59 -0
- data/spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb +33 -16
- data/spec/paperclip/io_adapters/uri_adapter_spec.rb +56 -8
- data/spec/paperclip/matchers/validate_attachment_size_matcher_spec.rb +1 -1
- data/spec/paperclip/media_type_spoof_detector_spec.rb +41 -0
- data/spec/paperclip/paperclip_spec.rb +13 -13
- data/spec/paperclip/processor_spec.rb +4 -4
- data/spec/paperclip/schema_spec.rb +46 -46
- data/spec/paperclip/storage/fog_spec.rb +5 -0
- data/spec/paperclip/storage/s3_spec.rb +6 -6
- data/spec/paperclip/style_spec.rb +0 -1
- data/spec/paperclip/thumbnail_spec.rb +8 -6
- data/spec/paperclip/url_generator_spec.rb +0 -1
- data/spec/spec_helper.rb +0 -1
- data/spec/support/model_reconstruction.rb +2 -2
- metadata +120 -20
- data/spec/support/conditional_filter_helper.rb +0 -5
| @@ -19,7 +19,7 @@ module Paperclip | |
| 19 19 | 
             
                #   store your files.  Remember that the bucket must be unique across
         | 
| 20 20 | 
             
                #   all of Amazon S3. If the bucket does not exist, Paperclip will
         | 
| 21 21 | 
             
                #   attempt to create it.
         | 
| 22 | 
            -
                # * +fog_file | 
| 22 | 
            +
                # * +fog_file+: This can be hash or lambda returning hash. The
         | 
| 23 23 | 
             
                #   value is used as base properties for new uploaded file.
         | 
| 24 24 | 
             
                # * +path+: This is the key under the bucket in which the file will
         | 
| 25 25 | 
             
                #   be stored. The URL will be constructed from the bucket and the
         | 
| @@ -117,6 +117,7 @@ module Paperclip | |
| 117 117 | 
             
                        raise if retried
         | 
| 118 118 | 
             
                        retried = true
         | 
| 119 119 | 
             
                        directory.save
         | 
| 120 | 
            +
                        file.rewind
         | 
| 120 121 | 
             
                        retry
         | 
| 121 122 | 
             
                      ensure
         | 
| 122 123 | 
             
                        file.rewind
         | 
| @@ -184,7 +185,7 @@ module Paperclip | |
| 184 185 | 
             
                  private
         | 
| 185 186 |  | 
| 186 187 | 
             
                  def convert_time(time)
         | 
| 187 | 
            -
                    if time.is_a?( | 
| 188 | 
            +
                    if time.is_a?(Integer)
         | 
| 188 189 | 
             
                      time = Time.now + time
         | 
| 189 190 | 
             
                    end
         | 
| 190 191 | 
             
                    time
         | 
    
        data/lib/paperclip/storage/s3.rb
    CHANGED
    
    | @@ -3,8 +3,8 @@ module Paperclip | |
| 3 3 | 
             
                # Amazon's S3 file hosting service is a scalable, easy place to store files for
         | 
| 4 4 | 
             
                # distribution. You can find out more about it at http://aws.amazon.com/s3
         | 
| 5 5 | 
             
                #
         | 
| 6 | 
            -
                # To use Paperclip with S3, include the +aws-sdk+ gem in your Gemfile:
         | 
| 7 | 
            -
                #   gem 'aws-sdk'
         | 
| 6 | 
            +
                # To use Paperclip with S3, include the +aws-sdk-s3+ gem in your Gemfile:
         | 
| 7 | 
            +
                #   gem 'aws-sdk-s3'
         | 
| 8 8 | 
             
                # There are a few S3-specific options for has_attached_file:
         | 
| 9 9 | 
             
                # * +s3_credentials+: Takes a path, a File, a Hash or a Proc. The path (or File) must point
         | 
| 10 10 | 
             
                #   to a YAML file containing the +access_key_id+ and +secret_access_key+ that Amazon
         | 
| @@ -94,8 +94,9 @@ module Paperclip | |
| 94 94 | 
             
                #   to interpolate. Keys should be unique, like filenames, and despite the fact that
         | 
| 95 95 | 
             
                #   S3 (strictly speaking) does not support directories, you can still use a / to
         | 
| 96 96 | 
             
                #   separate parts of your file name.
         | 
| 97 | 
            -
                # * +s3_host_name+: If you are using your bucket in Tokyo region | 
| 98 | 
            -
                #  | 
| 97 | 
            +
                # * +s3_host_name+: If you are using your bucket in Tokyo region
         | 
| 98 | 
            +
                #   etc, write host_name (e.g., 's3-ap-northeast-1.amazonaws.com').
         | 
| 99 | 
            +
                # * +s3_region+: For aws-sdk-s3, s3_region is required.
         | 
| 99 100 | 
             
                # * +s3_metadata+: These key/value pairs will be stored with the
         | 
| 100 101 | 
             
                #   object.  This option works by prefixing each key with
         | 
| 101 102 | 
             
                #   "x-amz-meta-" before sending it as a header on the object
         | 
| @@ -117,20 +118,16 @@ module Paperclip | |
| 117 118 | 
             
                #     :s3_storage_class => :REDUCED_REDUNDANCY
         | 
| 118 119 | 
             
                #
         | 
| 119 120 | 
             
                #   Other storage classes, such as <tt>:STANDARD_IA</tt>, are also available—see the
         | 
| 120 | 
            -
                #   documentation for the <tt>aws-sdk</tt> gem for the full list.
         | 
| 121 | 
            +
                #   documentation for the <tt>aws-sdk-s3</tt> gem for the full list.
         | 
| 121 122 |  | 
| 122 123 | 
             
                module S3
         | 
| 123 124 | 
             
                  def self.extended base
         | 
| 124 125 | 
             
                    begin
         | 
| 125 | 
            -
                      require  | 
| 126 | 
            +
                      require "aws-sdk-s3"
         | 
| 126 127 | 
             
                    rescue LoadError => e
         | 
| 127 | 
            -
                      e.message << " (You may need to install the aws-sdk gem)"
         | 
| 128 | 
            +
                      e.message << " (You may need to install the aws-sdk-s3 gem)"
         | 
| 128 129 | 
             
                      raise e
         | 
| 129 130 | 
             
                    end
         | 
| 130 | 
            -
                    if Gem::Version.new(Aws::VERSION) >= Gem::Version.new(2) &&
         | 
| 131 | 
            -
                       Gem::Version.new(Aws::VERSION) <= Gem::Version.new("2.0.33")
         | 
| 132 | 
            -
                      raise LoadError, "paperclip does not support aws-sdk versions 2.0.0 - 2.0.33.  Please upgrade aws-sdk to a newer version."
         | 
| 133 | 
            -
                    end
         | 
| 134 131 |  | 
| 135 132 | 
             
                    base.instance_eval do
         | 
| 136 133 | 
             
                      @s3_options     = @options[:s3_options]     || {}
         | 
| @@ -158,11 +155,6 @@ module Paperclip | |
| 158 155 |  | 
| 159 156 | 
             
                      @http_proxy = @options[:http_proxy] || nil
         | 
| 160 157 |  | 
| 161 | 
            -
                      if @options.has_key?(:use_accelerate_endpoint) &&
         | 
| 162 | 
            -
                          Gem::Version.new(Aws::VERSION) < Gem::Version.new("2.3.0")
         | 
| 163 | 
            -
                        raise LoadError, ":use_accelerate_endpoint is only available from aws-sdk version 2.3.0. Please upgrade aws-sdk to a newer version."
         | 
| 164 | 
            -
                      end
         | 
| 165 | 
            -
             | 
| 166 158 | 
             
                      @use_accelerate_endpoint = @options[:use_accelerate_endpoint]
         | 
| 167 159 | 
             
                    end
         | 
| 168 160 |  | 
    
        data/lib/paperclip/style.rb
    CHANGED
    
    
    
        data/lib/paperclip/thumbnail.rb
    CHANGED
    
    | @@ -84,9 +84,12 @@ module Paperclip | |
| 84 84 | 
             
                      source: "#{File.expand_path(src.path)}#{frame}",
         | 
| 85 85 | 
             
                      dest: File.expand_path(dst.path),
         | 
| 86 86 | 
             
                    )
         | 
| 87 | 
            -
                  rescue  | 
| 88 | 
            -
                     | 
| 89 | 
            -
             | 
| 87 | 
            +
                  rescue Terrapin::ExitStatusError => e
         | 
| 88 | 
            +
                    if @whiny
         | 
| 89 | 
            +
                      message = "There was an error processing the thumbnail for #{@basename}:\n" + e.message
         | 
| 90 | 
            +
                      raise Paperclip::Error, message
         | 
| 91 | 
            +
                    end
         | 
| 92 | 
            +
                  rescue Terrapin::CommandNotFoundError => e
         | 
| 90 93 | 
             
                    raise Paperclip::Errors::CommandNotFoundError.new("Could not run the `convert` command. Please install ImageMagick.")
         | 
| 91 94 | 
             
                  end
         | 
| 92 95 |  | 
| @@ -122,9 +125,9 @@ module Paperclip | |
| 122 125 | 
             
                    @identified_as_animated = ANIMATED_FORMATS.include? identify("-format %m :file", :file => "#{@file.path}[0]").to_s.downcase.strip
         | 
| 123 126 | 
             
                  end
         | 
| 124 127 | 
             
                  @identified_as_animated
         | 
| 125 | 
            -
                rescue  | 
| 128 | 
            +
                rescue Terrapin::ExitStatusError => e
         | 
| 126 129 | 
             
                  raise Paperclip::Error, "There was an error running `identify` for #{@basename}" if @whiny
         | 
| 127 | 
            -
                rescue  | 
| 130 | 
            +
                rescue Terrapin::CommandNotFoundError => e
         | 
| 128 131 | 
             
                  raise Paperclip::Errors::CommandNotFoundError.new("Could not run the `identify` command. Please install ImageMagick.")
         | 
| 129 132 | 
             
                end
         | 
| 130 133 | 
             
              end
         | 
| @@ -8,6 +8,10 @@ module Paperclip | |
| 8 8 | 
             
                    if Paperclip::MediaTypeSpoofDetector.using(adapter, value.original_filename, value.content_type).spoofed?
         | 
| 9 9 | 
             
                      record.errors.add(attribute, :spoofed_media_type)
         | 
| 10 10 | 
             
                    end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                    if adapter.tempfile
         | 
| 13 | 
            +
                      adapter.tempfile.close(true)
         | 
| 14 | 
            +
                    end
         | 
| 11 15 | 
             
                  end
         | 
| 12 16 | 
             
                end
         | 
| 13 17 |  | 
    
        data/lib/paperclip/version.rb
    CHANGED
    
    
    
        data/lib/paperclip.rb
    CHANGED
    
    | @@ -67,7 +67,7 @@ end | |
| 67 67 | 
             
            require 'mimemagic'
         | 
| 68 68 | 
             
            require 'mimemagic/overlay'
         | 
| 69 69 | 
             
            require 'logger'
         | 
| 70 | 
            -
            require ' | 
| 70 | 
            +
            require 'terrapin'
         | 
| 71 71 |  | 
| 72 72 | 
             
            require 'paperclip/railtie' if defined?(Rails::Railtie)
         | 
| 73 73 |  | 
| @@ -98,6 +98,7 @@ module Paperclip | |
| 98 98 | 
             
                  swallow_stderr: true,
         | 
| 99 99 | 
             
                  use_exif_orientation: true,
         | 
| 100 100 | 
             
                  whiny: true,
         | 
| 101 | 
            +
                  is_windows: Gem.win_platform?
         | 
| 101 102 | 
             
                }
         | 
| 102 103 | 
             
              end
         | 
| 103 104 |  | 
    
        data/paperclip.gemspec
    CHANGED
    
    | @@ -26,7 +26,7 @@ Gem::Specification.new do |s| | |
| 26 26 |  | 
| 27 27 | 
             
              s.add_dependency('activemodel', '>= 4.2.0')
         | 
| 28 28 | 
             
              s.add_dependency('activesupport', '>= 4.2.0')
         | 
| 29 | 
            -
              s.add_dependency(' | 
| 29 | 
            +
              s.add_dependency('terrapin', '~> 0.6.0')
         | 
| 30 30 | 
             
              s.add_dependency('mime-types')
         | 
| 31 31 | 
             
              s.add_dependency('mimemagic', '~> 0.3.0')
         | 
| 32 32 |  | 
| @@ -35,7 +35,7 @@ Gem::Specification.new do |s| | |
| 35 35 | 
             
              s.add_development_dependency('rspec', '~> 3.0')
         | 
| 36 36 | 
             
              s.add_development_dependency('appraisal')
         | 
| 37 37 | 
             
              s.add_development_dependency('mocha')
         | 
| 38 | 
            -
              s.add_development_dependency('aws-sdk' | 
| 38 | 
            +
              s.add_development_dependency('aws-sdk-s3')
         | 
| 39 39 | 
             
              s.add_development_dependency('bourne')
         | 
| 40 40 | 
             
              s.add_development_dependency('cucumber-rails')
         | 
| 41 41 | 
             
              s.add_development_dependency('cucumber-expressions', '4.0.3') # TODO: investigate failures on 4.0.4
         | 
| @@ -1,4 +1,3 @@ | |
| 1 | 
            -
            # encoding: utf-8
         | 
| 2 1 | 
             
            require 'spec_helper'
         | 
| 3 2 |  | 
| 4 3 | 
             
            describe Paperclip::Attachment do
         | 
| @@ -54,6 +53,22 @@ describe Paperclip::Attachment do | |
| 54 53 | 
             
                expect(dummy.avatar.path(:original)).to exist
         | 
| 55 54 | 
             
              end
         | 
| 56 55 |  | 
| 56 | 
            +
              it "reprocess works with virtual content_type attribute" do
         | 
| 57 | 
            +
                rebuild_class styles: { small: "100x>" }
         | 
| 58 | 
            +
                modify_table { |t| t.remove :avatar_content_type }
         | 
| 59 | 
            +
                Dummy.send :attr_accessor, :avatar_content_type
         | 
| 60 | 
            +
                Dummy.validates_attachment_content_type(
         | 
| 61 | 
            +
                  :avatar,
         | 
| 62 | 
            +
                  content_type: %w(image/jpeg image/png)
         | 
| 63 | 
            +
                )
         | 
| 64 | 
            +
                Dummy.create!(avatar: File.new(fixture_file("50x50.png"), "rb"))
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                dummy = Dummy.first
         | 
| 67 | 
            +
                dummy.avatar.reprocess!(:small)
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                expect(dummy.avatar.path(:small)).to exist
         | 
| 70 | 
            +
              end
         | 
| 71 | 
            +
             | 
| 57 72 | 
             
              context "having a not empty hash as a default option" do
         | 
| 58 73 | 
             
                before do
         | 
| 59 74 | 
             
                  @old_default_options = Paperclip::Attachment.default_options.dup
         | 
| @@ -1401,7 +1416,7 @@ describe Paperclip::Attachment do | |
| 1401 1416 |  | 
| 1402 1417 | 
             
                context "and avatar_file_size column" do
         | 
| 1403 1418 | 
             
                  before do
         | 
| 1404 | 
            -
                    ActiveRecord::Base.connection.add_column :dummies, :avatar_file_size, : | 
| 1419 | 
            +
                    ActiveRecord::Base.connection.add_column :dummies, :avatar_file_size, :bigint
         | 
| 1405 1420 | 
             
                    rebuild_class
         | 
| 1406 1421 | 
             
                    @dummy = Dummy.new
         | 
| 1407 1422 | 
             
                  end
         | 
| @@ -41,7 +41,7 @@ describe Paperclip::ContentTypeDetector do | |
| 41 41 | 
             
              end
         | 
| 42 42 |  | 
| 43 43 | 
             
              it 'returns a sensible default when the file command is missing' do
         | 
| 44 | 
            -
                Paperclip.stubs(:run).raises( | 
| 44 | 
            +
                Paperclip.stubs(:run).raises(Terrapin::CommandLineError.new)
         | 
| 45 45 | 
             
                @filename = "/path/to/something"
         | 
| 46 46 | 
             
                assert_equal "application/octet-stream", Paperclip::ContentTypeDetector.new(@filename).detect
         | 
| 47 47 | 
             
              end
         | 
| @@ -12,7 +12,7 @@ describe Paperclip::FileCommandContentTypeDetector do | |
| 12 12 | 
             
              end
         | 
| 13 13 |  | 
| 14 14 | 
             
              it 'returns a sensible default when the file command is missing' do
         | 
| 15 | 
            -
                Paperclip.stubs(:run).raises( | 
| 15 | 
            +
                Paperclip.stubs(:run).raises(Terrapin::CommandLineError.new)
         | 
| 16 16 | 
             
                @filename = "/path/to/something"
         | 
| 17 17 | 
             
                assert_equal "application/octet-stream",
         | 
| 18 18 | 
             
                  Paperclip::FileCommandContentTypeDetector.new(@filename).detect
         | 
| @@ -23,4 +23,18 @@ describe Paperclip::FileCommandContentTypeDetector do | |
| 23 23 | 
             
                assert_equal "application/octet-stream",
         | 
| 24 24 | 
             
                  Paperclip::FileCommandContentTypeDetector.new("windows").detect
         | 
| 25 25 | 
             
              end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
              context "#type_from_file_command" do
         | 
| 28 | 
            +
                let(:detector) { Paperclip::FileCommandContentTypeDetector.new("html") }
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                it "does work with the output of old versions of file" do
         | 
| 31 | 
            +
                  Paperclip.stubs(:run).returns("text/html charset=us-ascii")
         | 
| 32 | 
            +
                  expect(detector.detect).to eq("text/html")
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                it "does work with the output of new versions of file" do
         | 
| 36 | 
            +
                  Paperclip.stubs(:run).returns("text/html; charset=us-ascii")
         | 
| 37 | 
            +
                  expect(detector.detect).to eq("text/html")
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
              end
         | 
| 26 40 | 
             
            end
         | 
| @@ -1,16 +1,33 @@ | |
| 1 | 
            -
            # encoding: utf-8
         | 
| 2 1 | 
             
            require 'spec_helper'
         | 
| 3 2 | 
             
            require 'open-uri'
         | 
| 4 3 |  | 
| 5 4 | 
             
            describe 'Paperclip' do
         | 
| 5 | 
            +
              around do |example|
         | 
| 6 | 
            +
                files_before = ObjectSpace.each_object(Tempfile).select do |file|
         | 
| 7 | 
            +
                  file.path && File.file?(file.path)
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                example.run
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                files_after = ObjectSpace.each_object(Tempfile).select do |file|
         | 
| 13 | 
            +
                  file.path && File.file?(file.path)
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                diff = files_after - files_before
         | 
| 17 | 
            +
                expect(diff).to eq([]), "Leaked tempfiles: #{diff.inspect}"
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
             | 
| 6 20 | 
             
              context "Many models at once" do
         | 
| 7 21 | 
             
                before do
         | 
| 8 22 | 
             
                  rebuild_model
         | 
| 9 23 | 
             
                  @file = File.new(fixture_file("5k.png"), 'rb')
         | 
| 10 24 | 
             
                  # Deals with `Too many open files` error
         | 
| 11 | 
            -
                   | 
| 12 | 
            -
                  Dummy.import  | 
| 13 | 
            -
                   | 
| 25 | 
            +
                  dummies = Array.new(300) { Dummy.new avatar: @file }
         | 
| 26 | 
            +
                  Dummy.import dummies
         | 
| 27 | 
            +
                  # save attachment instances to run after hooks including tempfile cleanup
         | 
| 28 | 
            +
                  # since activerecord-import does not use our usually hooked-in hooks
         | 
| 29 | 
            +
                  # (such as after_save)
         | 
| 30 | 
            +
                  dummies.each { |dummy| dummy.avatar.save }
         | 
| 14 31 | 
             
                end
         | 
| 15 32 |  | 
| 16 33 | 
             
                after { @file.close }
         | 
| @@ -135,6 +152,14 @@ describe 'Paperclip' do | |
| 135 152 | 
             
                end
         | 
| 136 153 |  | 
| 137 154 | 
             
                it "allows us to selectively create each thumbnail" do
         | 
| 155 | 
            +
                  skip <<-EXPLANATION
         | 
| 156 | 
            +
            	#reprocess! calls #assign which calls Paperclip.io_adapters.for 
         | 
| 157 | 
            +
            	which creates the tempfile. #assign then calls #post_process_file which
         | 
| 158 | 
            +
            	calls MediaTypeSpoofDetectionValidator#validate_each which calls 
         | 
| 159 | 
            +
            	Paperclip.io_adapters.for, which creates another tempfile. That first
         | 
| 160 | 
            +
            	tempfile is the one that leaks.
         | 
| 161 | 
            +
                  EXPLANATION
         | 
| 162 | 
            +
             | 
| 138 163 | 
             
                  assert_file_not_exists(@thumb_small_path)
         | 
| 139 164 | 
             
                  assert_file_not_exists(@thumb_large_path)
         | 
| 140 165 |  | 
| @@ -159,7 +184,11 @@ describe 'Paperclip' do | |
| 159 184 | 
             
                  assert_not_equal File.size(@file.path), @dummy.avatar.size
         | 
| 160 185 | 
             
                end
         | 
| 161 186 |  | 
| 162 | 
            -
                after  | 
| 187 | 
            +
                after do
         | 
| 188 | 
            +
                  @file.close
         | 
| 189 | 
            +
                  # save attachment instance to run after hooks (including tempfile cleanup)
         | 
| 190 | 
            +
                  @dummy.avatar.save
         | 
| 191 | 
            +
                end
         | 
| 163 192 | 
             
              end
         | 
| 164 193 |  | 
| 165 194 | 
             
              context "A model with attachments scoped under an id" do
         | 
| @@ -347,6 +376,8 @@ describe 'Paperclip' do | |
| 347 376 | 
             
                it "is not ok with bad files" do
         | 
| 348 377 | 
             
                  @dummy.avatar = @bad_file
         | 
| 349 378 | 
             
                  assert ! @dummy.valid?
         | 
| 379 | 
            +
                  # save attachment instance to run after hooks (including tempfile cleanup)
         | 
| 380 | 
            +
                  @dummy.avatar.save
         | 
| 350 381 | 
             
                end
         | 
| 351 382 |  | 
| 352 383 | 
             
                it "knows the difference between good files, bad files, and not files when validating" do
         | 
| @@ -354,8 +385,13 @@ describe 'Paperclip' do | |
| 354 385 | 
             
                  @d2 = Dummy.find(@dummy.id)
         | 
| 355 386 | 
             
                  @d2.avatar = @file
         | 
| 356 387 | 
             
                  assert  @d2.valid?, @d2.errors.full_messages.inspect
         | 
| 388 | 
            +
                  # save attachment instance to run after hooks (including tempfile cleanup)
         | 
| 389 | 
            +
                  @d2.avatar.save
         | 
| 390 | 
            +
             | 
| 357 391 | 
             
                  @d2.avatar = @bad_file
         | 
| 358 392 | 
             
                  assert ! @d2.valid?
         | 
| 393 | 
            +
                  # save attachment instance to run after hooks (including tempfile cleanup)
         | 
| 394 | 
            +
                  @d2.avatar.save
         | 
| 359 395 | 
             
                end
         | 
| 360 396 |  | 
| 361 397 | 
             
                it "is able to reload without saving and not have the file disappear" do
         | 
| @@ -139,6 +139,15 @@ describe Paperclip::Interpolations do | |
| 139 139 | 
             
                assert_equal "000/000/023", Paperclip::Interpolations.id_partition(attachment, :style)
         | 
| 140 140 | 
             
              end
         | 
| 141 141 |  | 
| 142 | 
            +
              it "returns the partitioned id when the id is above 999_999_999" do
         | 
| 143 | 
            +
                attachment = mock
         | 
| 144 | 
            +
                attachment.expects(:id).
         | 
| 145 | 
            +
                  returns(Paperclip::Interpolations::ID_PARTITION_LIMIT)
         | 
| 146 | 
            +
                attachment.expects(:instance).returns(attachment)
         | 
| 147 | 
            +
                assert_equal "001/000/000/000",
         | 
| 148 | 
            +
                  Paperclip::Interpolations.id_partition(attachment, :style)
         | 
| 149 | 
            +
              end
         | 
| 150 | 
            +
             | 
| 142 151 | 
             
              it "returns the partitioned id of the attachment when the id is a string" do
         | 
| 143 152 | 
             
                attachment = mock
         | 
| 144 153 | 
             
                attachment.expects(:id).returns("32fnj23oio2f")
         | 
| @@ -93,9 +93,68 @@ describe Paperclip::AbstractAdapter do | |
| 93 93 | 
             
                end
         | 
| 94 94 | 
             
              end
         | 
| 95 95 |  | 
| 96 | 
            +
              context "#copy_to_tempfile" do
         | 
| 97 | 
            +
                around do |example|
         | 
| 98 | 
            +
                  FileUtils.module_eval do
         | 
| 99 | 
            +
                    class << self
         | 
| 100 | 
            +
                      alias paperclip_ln ln
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                      def ln(*)
         | 
| 103 | 
            +
                        raise Errno::EXDEV
         | 
| 104 | 
            +
                      end
         | 
| 105 | 
            +
                    end
         | 
| 106 | 
            +
                  end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                  example.run
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                  FileUtils.module_eval do
         | 
| 111 | 
            +
                    class << self
         | 
| 112 | 
            +
                      alias ln paperclip_ln
         | 
| 113 | 
            +
                      undef paperclip_ln
         | 
| 114 | 
            +
                    end
         | 
| 115 | 
            +
                  end
         | 
| 116 | 
            +
                end
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                it "should return a readable file even when linking fails" do
         | 
| 119 | 
            +
                  src = open(fixture_file("5k.png"), "rb")
         | 
| 120 | 
            +
                  expect(subject.send(:copy_to_tempfile, src).read).to eq src.read
         | 
| 121 | 
            +
                end
         | 
| 122 | 
            +
              end
         | 
| 123 | 
            +
             | 
| 96 124 | 
             
              context "#original_filename=" do
         | 
| 97 125 | 
             
                it "should not fail with a nil original filename" do
         | 
| 98 126 | 
             
                  expect { subject.original_filename = nil }.not_to raise_error
         | 
| 99 127 | 
             
                end
         | 
| 100 128 | 
             
              end
         | 
| 129 | 
            +
             | 
| 130 | 
            +
              context "#link_or_copy_file" do
         | 
| 131 | 
            +
                class TestLinkOrCopyAdapter < Paperclip::AbstractAdapter
         | 
| 132 | 
            +
                  public :copy_to_tempfile, :destination
         | 
| 133 | 
            +
                end
         | 
| 134 | 
            +
             | 
| 135 | 
            +
                subject { TestLinkOrCopyAdapter.new(nil) }
         | 
| 136 | 
            +
                let(:body) { "body" }
         | 
| 137 | 
            +
             | 
| 138 | 
            +
                let(:file) do
         | 
| 139 | 
            +
                  t = Tempfile.new("destination")
         | 
| 140 | 
            +
                  t.print(body)
         | 
| 141 | 
            +
                  t.rewind
         | 
| 142 | 
            +
                  t
         | 
| 143 | 
            +
                end
         | 
| 144 | 
            +
             | 
| 145 | 
            +
                after do
         | 
| 146 | 
            +
                  file.close
         | 
| 147 | 
            +
                  file.unlink
         | 
| 148 | 
            +
                end
         | 
| 149 | 
            +
             | 
| 150 | 
            +
                it "should be able to read the file" do
         | 
| 151 | 
            +
                  expect(subject.copy_to_tempfile(file).read).to eq(body)
         | 
| 152 | 
            +
                end
         | 
| 153 | 
            +
             | 
| 154 | 
            +
                it "should be able to reopen the file after symlink has failed" do
         | 
| 155 | 
            +
                  FileUtils.expects(:ln).raises(Errno::EXDEV)
         | 
| 156 | 
            +
             | 
| 157 | 
            +
                  expect(subject.copy_to_tempfile(file).read).to eq(body)
         | 
| 158 | 
            +
                end
         | 
| 159 | 
            +
              end
         | 
| 101 160 | 
             
            end
         | 
| @@ -3,10 +3,9 @@ require 'spec_helper' | |
| 3 3 | 
             
            describe Paperclip::HttpUrlProxyAdapter do
         | 
| 4 4 | 
             
              before do
         | 
| 5 5 | 
             
                @open_return = StringIO.new("xxx")
         | 
| 6 | 
            -
                @open_return.stubs(: | 
| 7 | 
            -
                 | 
| 8 | 
            -
             | 
| 9 | 
            -
                  stubs(:download_content).returns(@open_return)
         | 
| 6 | 
            +
                @open_return.stubs(:meta).returns("content-type" => "image/png")
         | 
| 7 | 
            +
                Paperclip::HttpUrlProxyAdapter.any_instance.stubs(:download_content).
         | 
| 8 | 
            +
                  returns(@open_return)
         | 
| 10 9 | 
             
                Paperclip::HttpUrlProxyAdapter.register
         | 
| 11 10 | 
             
              end
         | 
| 12 11 |  | 
| @@ -69,17 +68,18 @@ describe Paperclip::HttpUrlProxyAdapter do | |
| 69 68 | 
             
              end
         | 
| 70 69 |  | 
| 71 70 | 
             
              context "a url with query params" do
         | 
| 72 | 
            -
                 | 
| 73 | 
            -
                  @url = "https://github.com/thoughtbot/paperclip?file=test"
         | 
| 74 | 
            -
                  @subject = Paperclip.io_adapters.for(@url)
         | 
| 75 | 
            -
                end
         | 
| 71 | 
            +
                subject { Paperclip.io_adapters.for(url) }
         | 
| 76 72 |  | 
| 77 | 
            -
                after  | 
| 78 | 
            -
             | 
| 79 | 
            -
                 | 
| 73 | 
            +
                after { subject.close }
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                let(:url) { "https://github.com/thoughtbot/paperclip?file=test" }
         | 
| 80 76 |  | 
| 81 77 | 
             
                it "returns a file name" do
         | 
| 82 | 
            -
                  assert_equal "paperclip",  | 
| 78 | 
            +
                  assert_equal "paperclip", subject.original_filename
         | 
| 79 | 
            +
                end
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                it "preserves params" do
         | 
| 82 | 
            +
                  assert_equal url, subject.instance_variable_get(:@target).to_s
         | 
| 83 83 | 
             
                end
         | 
| 84 84 | 
             
              end
         | 
| 85 85 |  | 
| @@ -107,15 +107,32 @@ describe Paperclip::HttpUrlProxyAdapter do | |
| 107 107 | 
             
              end
         | 
| 108 108 |  | 
| 109 109 | 
             
              context "a url with special characters in the filename" do
         | 
| 110 | 
            -
                 | 
| 110 | 
            +
                before do
         | 
| 111 111 | 
             
                  Paperclip::HttpUrlProxyAdapter.any_instance.stubs(:download_content).
         | 
| 112 112 | 
             
                    returns(@open_return)
         | 
| 113 | 
            -
             | 
| 114 | 
            -
             | 
| 115 | 
            -
             | 
| 113 | 
            +
                end
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                let(:filename) do
         | 
| 116 | 
            +
                  "paperclip-%C3%B6%C3%A4%C3%BC%E5%AD%97%C2%B4%C2%BD%E2%99%A5"\
         | 
| 116 117 | 
             
                    "%C3%98%C2%B2%C3%88.png"
         | 
| 118 | 
            +
                end
         | 
| 119 | 
            +
                let(:url) { "https://github.com/thoughtbot/paperclip-öäü字´½♥زÈ.png" }
         | 
| 117 120 |  | 
| 121 | 
            +
                subject { Paperclip.io_adapters.for(url) }
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                it "returns a encoded filename" do
         | 
| 118 124 | 
             
                  assert_equal filename, subject.original_filename
         | 
| 119 125 | 
             
                end
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                context "when already URI encoded" do
         | 
| 128 | 
            +
                  let(:url) do
         | 
| 129 | 
            +
                    "https://github.com/thoughtbot/paperclip-%C3%B6%C3%A4%C3%BC%E5%AD%97"\
         | 
| 130 | 
            +
                    "%C2%B4%C2%BD%E2%99%A5%C3%98%C2%B2%C3%88.png"
         | 
| 131 | 
            +
                  end
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                  it "returns a encoded filename" do
         | 
| 134 | 
            +
                    assert_equal filename, subject.original_filename
         | 
| 135 | 
            +
                  end
         | 
| 136 | 
            +
                end
         | 
| 120 137 | 
             
              end
         | 
| 121 138 | 
             
            end
         | 
| @@ -16,6 +16,8 @@ describe Paperclip::UriAdapter do | |
| 16 16 | 
             
              end
         | 
| 17 17 |  | 
| 18 18 | 
             
              context "a new instance" do
         | 
| 19 | 
            +
                let(:meta) { { "content-type" => "image/png" } }
         | 
| 20 | 
            +
             | 
| 19 21 | 
             
                before do
         | 
| 20 22 | 
             
                  Paperclip::UriAdapter.any_instance.
         | 
| 21 23 | 
             
                    stubs(:download_content).returns(@open_return)
         | 
| @@ -62,7 +64,7 @@ describe Paperclip::UriAdapter do | |
| 62 64 | 
             
                  assert_equal 'image/png', @subject.content_type
         | 
| 63 65 | 
             
                end
         | 
| 64 66 |  | 
| 65 | 
            -
                it  | 
| 67 | 
            +
                it "accepts an original_filename" do
         | 
| 66 68 | 
             
                  @subject.original_filename = 'image.png'
         | 
| 67 69 | 
             
                  assert_equal 'image.png', @subject.original_filename
         | 
| 68 70 | 
             
                end
         | 
| @@ -71,6 +73,7 @@ describe Paperclip::UriAdapter do | |
| 71 73 |  | 
| 72 74 | 
             
              context "a directory index url" do
         | 
| 73 75 | 
             
                let(:content_type) { "text/html" }
         | 
| 76 | 
            +
                let(:meta) { { "content-type" => "text/html" } }
         | 
| 74 77 |  | 
| 75 78 | 
             
                before do
         | 
| 76 79 | 
             
                  Paperclip::UriAdapter.any_instance.
         | 
| @@ -105,23 +108,68 @@ describe Paperclip::UriAdapter do | |
| 105 108 |  | 
| 106 109 | 
             
              context "a url with content disposition headers" do
         | 
| 107 110 | 
             
                let(:file_name) { "test_document.pdf" }
         | 
| 108 | 
            -
                let(: | 
| 109 | 
            -
                  {
         | 
| 110 | 
            -
                    "content-disposition" => "attachment; filename=\"#{file_name}\";",
         | 
| 111 | 
            -
                  }
         | 
| 112 | 
            -
                end
         | 
| 111 | 
            +
                let(:filename_from_path) { "paperclip" }
         | 
| 113 112 |  | 
| 114 113 | 
             
                before do
         | 
| 115 114 | 
             
                  Paperclip::UriAdapter.any_instance.
         | 
| 116 115 | 
             
                    stubs(:download_content).returns(@open_return)
         | 
| 117 116 |  | 
| 118 | 
            -
                  @uri = URI.parse( | 
| 117 | 
            +
                  @uri = URI.parse(
         | 
| 118 | 
            +
                    "https://github.com/thoughtbot/#{filename_from_path}?file=test")
         | 
| 119 | 
            +
                end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                it "returns file name from path" do
         | 
| 122 | 
            +
                  meta["content-disposition"] = "inline;"
         | 
| 123 | 
            +
             | 
| 119 124 | 
             
                  @subject = Paperclip.io_adapters.for(@uri)
         | 
| 125 | 
            +
             | 
| 126 | 
            +
                  assert_equal filename_from_path, @subject.original_filename
         | 
| 120 127 | 
             
                end
         | 
| 121 128 |  | 
| 122 | 
            -
                it "returns a file name" do
         | 
| 129 | 
            +
                it "returns a file name enclosed in double quotes" do
         | 
| 130 | 
            +
                  file_name = "john's test document.pdf"
         | 
| 131 | 
            +
                  meta["content-disposition"] = "attachment; filename=\"#{file_name}\";"
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                  @subject = Paperclip.io_adapters.for(@uri)
         | 
| 134 | 
            +
             | 
| 135 | 
            +
                  assert_equal file_name, @subject.original_filename
         | 
| 136 | 
            +
                end
         | 
| 137 | 
            +
             | 
| 138 | 
            +
                it "returns a file name not enclosed in double quotes" do
         | 
| 139 | 
            +
                  meta["content-disposition"] = "ATTACHMENT; FILENAME=#{file_name};"
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                  @subject = Paperclip.io_adapters.for(@uri)
         | 
| 142 | 
            +
             | 
| 143 | 
            +
                  assert_equal file_name, @subject.original_filename
         | 
| 144 | 
            +
                end
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                it "does not crash when an empty filename is given" do
         | 
| 147 | 
            +
                  meta["content-disposition"] = "ATTACHMENT; FILENAME=\"\";"
         | 
| 148 | 
            +
             | 
| 149 | 
            +
                  @subject = Paperclip.io_adapters.for(@uri)
         | 
| 150 | 
            +
             | 
| 151 | 
            +
                  assert_equal "", @subject.original_filename
         | 
| 152 | 
            +
                end
         | 
| 153 | 
            +
             | 
| 154 | 
            +
                it "returns a file name ignoring RFC 5987 encoding" do
         | 
| 155 | 
            +
                  meta["content-disposition"] =
         | 
| 156 | 
            +
                    "attachment; filename=#{file_name}; filename* = utf-8''%e2%82%ac%20rates"
         | 
| 157 | 
            +
             | 
| 158 | 
            +
                  @subject = Paperclip.io_adapters.for(@uri)
         | 
| 159 | 
            +
             | 
| 123 160 | 
             
                  assert_equal file_name, @subject.original_filename
         | 
| 124 161 | 
             
                end
         | 
| 162 | 
            +
             | 
| 163 | 
            +
                context "when file name has consecutive periods" do
         | 
| 164 | 
            +
                  let(:file_name) { "test_document..pdf" }
         | 
| 165 | 
            +
             | 
| 166 | 
            +
                  it "returns a file name" do
         | 
| 167 | 
            +
                    @uri = URI.parse(
         | 
| 168 | 
            +
                      "https://github.com/thoughtbot/#{file_name}?file=test")
         | 
| 169 | 
            +
                    @subject = Paperclip.io_adapters.for(@uri)
         | 
| 170 | 
            +
                    assert_equal file_name, @subject.original_filename
         | 
| 171 | 
            +
                  end
         | 
| 172 | 
            +
                end
         | 
| 125 173 | 
             
              end
         | 
| 126 174 |  | 
| 127 175 | 
             
              context "a url with restricted characters in the filename" do
         | 
| @@ -7,7 +7,7 @@ describe Paperclip::Shoulda::Matchers::ValidateAttachmentSizeMatcher do | |
| 7 7 | 
             
              before do
         | 
| 8 8 | 
             
                reset_table("dummies") do |d|
         | 
| 9 9 | 
             
                  d.string :avatar_file_name
         | 
| 10 | 
            -
                  d. | 
| 10 | 
            +
                  d.bigint :avatar_file_size
         | 
| 11 11 | 
             
                end
         | 
| 12 12 | 
             
                reset_class "Dummy"
         | 
| 13 13 | 
             
                Dummy.do_not_validate_attachment_file_type :avatar
         |