kt-paperclip 7.2.2 → 8.0.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.
Files changed (203) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/README.md +24 -56
  4. data/lib/generators/paperclip/paperclip_generator.rb +3 -1
  5. data/lib/kt-paperclip.rb +2 -0
  6. data/lib/paperclip/attachment.rb +49 -30
  7. data/lib/paperclip/attachment_registry.rb +2 -0
  8. data/lib/paperclip/callbacks.rb +7 -4
  9. data/lib/paperclip/commands/imagemagick/geometry_parser.rb +63 -0
  10. data/lib/paperclip/commands/imagemagick/version_detector.rb +41 -0
  11. data/lib/paperclip/commands/imagemagick.rb +44 -0
  12. data/lib/paperclip/commands/runner.rb +38 -0
  13. data/lib/paperclip/commands/unix_file.rb +28 -0
  14. data/lib/paperclip/content_type_detector.rb +31 -32
  15. data/lib/paperclip/errors.rb +2 -0
  16. data/lib/paperclip/file_command_content_type_detector.rb +11 -12
  17. data/lib/paperclip/filename_cleaner.rb +2 -0
  18. data/lib/paperclip/geometry.rb +22 -7
  19. data/lib/paperclip/geometry_detector_factory.rb +11 -31
  20. data/lib/paperclip/geometry_parser_factory.rb +13 -17
  21. data/lib/paperclip/glue.rb +2 -0
  22. data/lib/paperclip/has_attached_file.rb +2 -0
  23. data/lib/paperclip/helpers.rb +5 -25
  24. data/lib/paperclip/interpolations/plural_cache.rb +2 -0
  25. data/lib/paperclip/interpolations.rb +2 -0
  26. data/lib/paperclip/io_adapters/abstract_adapter.rb +3 -1
  27. data/lib/paperclip/io_adapters/attachment_adapter.rb +11 -0
  28. data/lib/paperclip/io_adapters/data_uri_adapter.rb +2 -0
  29. data/lib/paperclip/io_adapters/empty_string_adapter.rb +2 -0
  30. data/lib/paperclip/io_adapters/file_adapter.rb +2 -0
  31. data/lib/paperclip/io_adapters/http_url_proxy_adapter.rb +2 -0
  32. data/lib/paperclip/io_adapters/identity_adapter.rb +2 -0
  33. data/lib/paperclip/io_adapters/nil_adapter.rb +2 -0
  34. data/lib/paperclip/io_adapters/registry.rb +2 -0
  35. data/lib/paperclip/io_adapters/stringio_adapter.rb +2 -0
  36. data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +2 -0
  37. data/lib/paperclip/io_adapters/uri_adapter.rb +5 -13
  38. data/lib/paperclip/locales/fr.yml +18 -0
  39. data/lib/paperclip/locales/gd.yml +1 -1
  40. data/lib/paperclip/logger.rb +2 -0
  41. data/lib/paperclip/matchers/have_attached_file_matcher.rb +2 -0
  42. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +5 -3
  43. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +2 -0
  44. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +2 -0
  45. data/lib/paperclip/matchers.rb +2 -0
  46. data/lib/paperclip/media_type_spoof_detector.rb +3 -10
  47. data/lib/paperclip/missing_attachment_styles.rb +2 -0
  48. data/lib/paperclip/processor.rb +6 -19
  49. data/lib/paperclip/processor_helpers.rb +2 -0
  50. data/lib/paperclip/rails_environment.rb +2 -0
  51. data/lib/paperclip/railtie.rb +2 -0
  52. data/lib/paperclip/schema.rb +6 -4
  53. data/lib/paperclip/storage/filesystem.rb +2 -0
  54. data/lib/paperclip/storage/fog.rb +13 -4
  55. data/lib/paperclip/storage/s3.rb +27 -5
  56. data/lib/paperclip/storage.rb +2 -0
  57. data/lib/paperclip/style.rb +2 -0
  58. data/lib/paperclip/tempfile.rb +2 -0
  59. data/lib/paperclip/tempfile_factory.rb +2 -0
  60. data/lib/paperclip/thumbnail.rb +9 -10
  61. data/lib/paperclip/url_generator.rb +2 -0
  62. data/lib/paperclip/validators/attachment_content_type_validator.rb +2 -0
  63. data/lib/paperclip/validators/attachment_file_name_validator.rb +2 -0
  64. data/lib/paperclip/validators/attachment_file_type_ignorance_validator.rb +2 -0
  65. data/lib/paperclip/validators/attachment_presence_validator.rb +2 -0
  66. data/lib/paperclip/validators/attachment_size_validator.rb +2 -0
  67. data/lib/paperclip/validators/media_type_spoof_detection_validator.rb +2 -0
  68. data/lib/paperclip/validators.rb +2 -0
  69. data/lib/paperclip/version.rb +3 -1
  70. data/lib/paperclip.rb +25 -4
  71. data/lib/tasks/paperclip.rake +9 -4
  72. data/shoulda_macros/paperclip.rb +2 -0
  73. metadata +19 -538
  74. data/.codeclimate.yml +0 -17
  75. data/.github/FUNDING.yml +0 -3
  76. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -38
  77. data/.github/ISSUE_TEMPLATE/custom.md +0 -10
  78. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
  79. data/.gitignore +0 -19
  80. data/.hound.yml +0 -3
  81. data/.rubocop.yml +0 -1061
  82. data/.travis.yml +0 -45
  83. data/Appraisals +0 -30
  84. data/CONTRIBUTING.md +0 -85
  85. data/Gemfile +0 -19
  86. data/NEWS +0 -554
  87. data/RELEASING.md +0 -17
  88. data/Rakefile +0 -52
  89. data/UPGRADING +0 -17
  90. data/features/basic_integration.feature +0 -85
  91. data/features/migration.feature +0 -29
  92. data/features/rake_tasks.feature +0 -62
  93. data/features/step_definitions/attachment_steps.rb +0 -120
  94. data/features/step_definitions/html_steps.rb +0 -15
  95. data/features/step_definitions/rails_steps.rb +0 -257
  96. data/features/step_definitions/s3_steps.rb +0 -14
  97. data/features/step_definitions/web_steps.rb +0 -106
  98. data/features/support/env.rb +0 -12
  99. data/features/support/fakeweb.rb +0 -11
  100. data/features/support/file_helpers.rb +0 -34
  101. data/features/support/fixtures/boot_config.txt +0 -15
  102. data/features/support/fixtures/gemfile.txt +0 -5
  103. data/features/support/fixtures/preinitializer.txt +0 -20
  104. data/features/support/paths.rb +0 -28
  105. data/features/support/rails.rb +0 -39
  106. data/features/support/selectors.rb +0 -19
  107. data/gemfiles/4.2.gemfile +0 -20
  108. data/gemfiles/5.0.gemfile +0 -20
  109. data/gemfiles/5.1.gemfile +0 -20
  110. data/gemfiles/5.2.gemfile +0 -20
  111. data/gemfiles/6.0.gemfile +0 -20
  112. data/gemfiles/6.1.gemfile +0 -21
  113. data/gemfiles/7.0.gemfile +0 -21
  114. data/paperclip.gemspec +0 -50
  115. data/spec/database.yml +0 -4
  116. data/spec/paperclip/attachment_definitions_spec.rb +0 -13
  117. data/spec/paperclip/attachment_processing_spec.rb +0 -79
  118. data/spec/paperclip/attachment_registry_spec.rb +0 -158
  119. data/spec/paperclip/attachment_spec.rb +0 -1590
  120. data/spec/paperclip/content_type_detector_spec.rb +0 -54
  121. data/spec/paperclip/file_command_content_type_detector_spec.rb +0 -40
  122. data/spec/paperclip/filename_cleaner_spec.rb +0 -13
  123. data/spec/paperclip/geometry_detector_spec.rb +0 -47
  124. data/spec/paperclip/geometry_parser_spec.rb +0 -73
  125. data/spec/paperclip/geometry_spec.rb +0 -267
  126. data/spec/paperclip/glue_spec.rb +0 -63
  127. data/spec/paperclip/has_attached_file_spec.rb +0 -78
  128. data/spec/paperclip/integration_spec.rb +0 -702
  129. data/spec/paperclip/interpolations_spec.rb +0 -270
  130. data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +0 -160
  131. data/spec/paperclip/io_adapters/attachment_adapter_spec.rb +0 -140
  132. data/spec/paperclip/io_adapters/data_uri_adapter_spec.rb +0 -88
  133. data/spec/paperclip/io_adapters/empty_string_adapter_spec.rb +0 -17
  134. data/spec/paperclip/io_adapters/file_adapter_spec.rb +0 -131
  135. data/spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb +0 -142
  136. data/spec/paperclip/io_adapters/identity_adapter_spec.rb +0 -8
  137. data/spec/paperclip/io_adapters/nil_adapter_spec.rb +0 -25
  138. data/spec/paperclip/io_adapters/registry_spec.rb +0 -35
  139. data/spec/paperclip/io_adapters/stringio_adapter_spec.rb +0 -64
  140. data/spec/paperclip/io_adapters/uploaded_file_adapter_spec.rb +0 -146
  141. data/spec/paperclip/io_adapters/uri_adapter_spec.rb +0 -231
  142. data/spec/paperclip/matchers/have_attached_file_matcher_spec.rb +0 -19
  143. data/spec/paperclip/matchers/validate_attachment_content_type_matcher_spec.rb +0 -108
  144. data/spec/paperclip/matchers/validate_attachment_presence_matcher_spec.rb +0 -69
  145. data/spec/paperclip/matchers/validate_attachment_size_matcher_spec.rb +0 -88
  146. data/spec/paperclip/media_type_spoof_detector_spec.rb +0 -126
  147. data/spec/paperclip/meta_class_spec.rb +0 -30
  148. data/spec/paperclip/paperclip_missing_attachment_styles_spec.rb +0 -88
  149. data/spec/paperclip/paperclip_spec.rb +0 -196
  150. data/spec/paperclip/plural_cache_spec.rb +0 -37
  151. data/spec/paperclip/processor_helpers_spec.rb +0 -57
  152. data/spec/paperclip/processor_spec.rb +0 -26
  153. data/spec/paperclip/rails_environment_spec.rb +0 -30
  154. data/spec/paperclip/rake_spec.rb +0 -103
  155. data/spec/paperclip/schema_spec.rb +0 -252
  156. data/spec/paperclip/storage/filesystem_spec.rb +0 -102
  157. data/spec/paperclip/storage/fog_spec.rb +0 -606
  158. data/spec/paperclip/storage/s3_live_spec.rb +0 -188
  159. data/spec/paperclip/storage/s3_spec.rb +0 -1878
  160. data/spec/paperclip/style_spec.rb +0 -251
  161. data/spec/paperclip/tempfile_factory_spec.rb +0 -33
  162. data/spec/paperclip/tempfile_spec.rb +0 -35
  163. data/spec/paperclip/thumbnail_spec.rb +0 -504
  164. data/spec/paperclip/url_generator_spec.rb +0 -231
  165. data/spec/paperclip/validators/attachment_content_type_validator_spec.rb +0 -410
  166. data/spec/paperclip/validators/attachment_file_name_validator_spec.rb +0 -249
  167. data/spec/paperclip/validators/attachment_presence_validator_spec.rb +0 -85
  168. data/spec/paperclip/validators/attachment_size_validator_spec.rb +0 -325
  169. data/spec/paperclip/validators/media_type_spoof_detection_validator_spec.rb +0 -48
  170. data/spec/paperclip/validators_spec.rb +0 -179
  171. data/spec/spec_helper.rb +0 -46
  172. data/spec/support/assertions.rb +0 -84
  173. data/spec/support/fake_model.rb +0 -24
  174. data/spec/support/fake_rails.rb +0 -12
  175. data/spec/support/fixtures/12k.png +0 -0
  176. data/spec/support/fixtures/50x50.png +0 -0
  177. data/spec/support/fixtures/5k.png +0 -0
  178. data/spec/support/fixtures/animated +0 -0
  179. data/spec/support/fixtures/animated.gif +0 -0
  180. data/spec/support/fixtures/animated.unknown +0 -0
  181. data/spec/support/fixtures/aws_s3.yml +0 -13
  182. data/spec/support/fixtures/bad.png +0 -1
  183. data/spec/support/fixtures/empty.html +0 -1
  184. data/spec/support/fixtures/empty.xlsx +0 -0
  185. data/spec/support/fixtures/fog.yml +0 -8
  186. data/spec/support/fixtures/rotated.jpg +0 -0
  187. data/spec/support/fixtures/s3.yml +0 -8
  188. data/spec/support/fixtures/sample.xlsm +0 -0
  189. data/spec/support/fixtures/spaced file.jpg +0 -0
  190. data/spec/support/fixtures/spaced file.png +0 -0
  191. data/spec/support/fixtures/text.txt +0 -1
  192. data/spec/support/fixtures/twopage.pdf +0 -0
  193. data/spec/support/fixtures/uppercase.PNG +0 -0
  194. data/spec/support/matchers/accept.rb +0 -5
  195. data/spec/support/matchers/exist.rb +0 -5
  196. data/spec/support/matchers/have_column.rb +0 -23
  197. data/spec/support/mock_attachment.rb +0 -24
  198. data/spec/support/mock_interpolator.rb +0 -24
  199. data/spec/support/mock_url_generator_builder.rb +0 -26
  200. data/spec/support/model_reconstruction.rb +0 -72
  201. data/spec/support/reporting.rb +0 -11
  202. data/spec/support/test_data.rb +0 -13
  203. data/spec/support/version_helper.rb +0 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a7308352f1d792e5e861ba828d1eb3994b5956fc51df06a4cbfedfe134ce105d
4
- data.tar.gz: be4d4161c411a18edaf2a92b5a48d746d87d01f3d5a6e4fe5fecc20f87ad42a4
3
+ metadata.gz: 57acb40c010d089179840fb06116bb36527035ce5e6ddaa25531d2d24067456f
4
+ data.tar.gz: f49b37dbd63550be17c59b47ce930981dae6f7d88461cf90721925051e579efa
5
5
  SHA512:
6
- metadata.gz: e202f7d5a1a9466f69118e485c5c747f10942644337940b6141ffb41904118353cab09858fbdabf4e68ba87d9e5199109a1a1525d7eaeea4a1601ba9e384459f
7
- data.tar.gz: 20fb1d6bd39a2d21a5b2f627d5ab92aba95ae88d523319de7b06e5e0983c281e76ae218a6bccf64fdc16362652cb1cc1251eab7fdacc14b6428b8dbafd2bdc81
6
+ metadata.gz: f92b7453a259e25763375ba727dc262910ec647e54017182befa98e0330e6ac5890cd76ab27476a3be6725de35aeb8b85f73db463ad75007370d0076ed3220bb
7
+ data.tar.gz: dae535db1d37087c4505aaa0db691c2e300377755c9345ef412a28dfde1bf55f64f169d6f438d0285672db9bc8681629708c1c366e719cfcb2773d89f6ad5906
data/LICENSE CHANGED
@@ -1,9 +1,9 @@
1
-
2
1
  LICENSE
3
2
 
4
3
  The MIT License
5
4
 
6
5
  Copyright (c) 2008-2016 Jon Yurek and thoughtbot, inc.
6
+ Copyright (c) 2019-2025 Kreeti Technologies Pvt Ltd.
7
7
 
8
8
  Permission is hereby granted, free of charge, to any person obtaining a copy
9
9
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -93,73 +93,41 @@ Requirements
93
93
  Paperclip now requires Ruby version **>= 2.3** and Rails version **>= 4.2**
94
94
  (only if you're going to use Paperclip with Ruby on Rails).
95
95
 
96
- ### Image Processor
96
+ ### ImageMagick Image Processor
97
97
 
98
- [ImageMagick](http://www.imagemagick.org) must be installed and Paperclip must have access to it. To ensure
99
- that it does, on your command line, run `which convert` (one of the ImageMagick
100
- utilities). This will give you the path where that utility is installed. For
101
- example, it might return `/usr/local/bin/convert`.
98
+ [ImageMagick](http://www.imagemagick.org) must be installed and Paperclip must have access to it.
99
+ Refer to ImageMagick's [installations instructions](https://imagemagick.org/download/).
100
+ ImageMagick 7 is the latest version. As of April 2026, some package managers such as `apt`
101
+ still install ImageMagick 6.
102
102
 
103
- Then, in your environment config file, let Paperclip know to look there by adding that
104
- directory to its path.
105
-
106
- In development mode, you might add this line to `config/environments/development.rb)`:
103
+ Paperclip supports both ImageMagick versions 6 and 7, and will auto-detect your version.
104
+ You may enforce a specific version in an initializer such as `config/initializers/paperclip.rb`:
107
105
 
108
106
  ```ruby
109
- Paperclip.options[:command_path] = "/usr/local/bin/"
107
+ Paperclip.options[:imagemagick_version] = "7"
110
108
  ```
111
109
 
112
- If you're on Mac OS X, you'll want to run the following with [Homebrew](http://www.brew.sh):
113
-
114
- brew install imagemagick
115
-
116
- If you are dealing with pdf uploads or running the test suite, you'll also need
117
- to install GhostScript. On Mac OS X, you can also install that using Homebrew:
118
-
119
- brew install gs
120
-
121
- If you are on Ubuntu (or any Debian base Linux distribution), you'll want to run
122
- the following with apt-get:
123
-
124
- sudo apt-get install imagemagick -y
125
-
126
- ### `file`
127
-
128
- The Unix [`file` command](https://en.wikipedia.org/wiki/File_(command)) is required for content-type checking.
129
- This utility isn't available in Windows, but comes bundled with Ruby [Devkit](https://github.com/oneclick/rubyinstaller/wiki/Development-Kit),
130
- so Windows users must make sure that the devkit is installed and added to the system `PATH`.
131
-
132
- **Manual Installation**
133
-
134
- If you're using Windows 7+ as a development environment, you may need to install the `file.exe` application manually. The `file spoofing` system in Paperclip 4+ relies on this; if you don't have it working, you'll receive `Validation failed: Upload file has an extension that does not match its contents.` errors.
110
+ Please ensure ImageMagick is in your environment path, or alternatively set
111
+ the path manually in an initializer:
135
112
 
136
- To manually install, you should perform the following:
137
-
138
- > **Download & install `file` from [this URL](http://gnuwin32.sourceforge.net/packages/file.htm)**
139
-
140
- To test, you can use the image below:
141
- ![untitled](https://cloud.githubusercontent.com/assets/1104431/4524452/a1f8cce4-4d44-11e4-872e-17adb96f79c9.png)
142
-
143
- Next, you need to integrate with your environment - preferably through the `PATH` variable, or by changing your `config/environments/development.rb` file
144
-
145
- **PATH**
146
-
147
- 1. Click "Start"
148
- 2. On "Computer", right-click and select "Properties"
149
- 3. In Properties, select "Advanced System Settings"
150
- 4. Click the "Environment Variables" button
151
- 5. Locate the "PATH" var - at the end, add the path to your newly installed `file.exe` (typically `C:\Program Files (x86)\GnuWin32\bin`)
152
- 6. Restart any CMD shells you have open & see if it works
113
+ ```ruby
114
+ Paperclip.options[:imagemagick_path] = "/usr/local/bin/"
115
+ ```
153
116
 
154
- OR
117
+ ### Optional: Unix `file` Command
155
118
 
156
- **Environment**
119
+ Paperclip uses the [Marcel gem](https://github.com/rails/marcel) to detect file content types.
120
+ If Marcel cannot detect the type, the [Unix `file` command](https://en.wikipedia.org/wiki/File_(command))
121
+ is used as an optional fallback. To use it, ensure `file` is in your environment path,
122
+ or alternatively set its path manually in an initializer:
157
123
 
158
- 1. Open `config/environments/development.rb`
159
- 2. Add the following line: `Paperclip.options[:command_path] = 'C:\Program Files (x86)\GnuWin32\bin'`
160
- 3. Restart your Rails server
124
+ ```ruby
125
+ Paperclip.options[:file_command_path] = "/usr/local/bin/"
126
+ ```
161
127
 
162
- Either of these methods will give your Rails setup access to the `file.exe` functionality, thus providing the ability to check the contents of a file (fixing the spoofing problem)
128
+ Windows users should install the `file` utility via the Ruby Installer for Windows'
129
+ [DevKit](https://github.com/oneclick/rubyinstaller/wiki/Development-Kit), or alternatively,
130
+ by installing [MSYS2](https://www.msys2.org/) which provides Unix utilities for Windows.
163
131
 
164
132
  ---
165
133
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "rails/generators/active_record"
2
4
 
3
5
  class PaperclipGenerator < ActiveRecord::Generators::Base
@@ -31,6 +33,6 @@ class PaperclipGenerator < ActiveRecord::Generators::Base
31
33
  end
32
34
 
33
35
  def migration_version
34
- "[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]" if Rails.version.first.to_i > 4
36
+ "[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
35
37
  end
36
38
  end
data/lib/kt-paperclip.rb CHANGED
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "paperclip"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "uri"
2
4
  require "paperclip/url_generator"
3
5
  require "active_support/deprecation"
@@ -10,30 +12,31 @@ module Paperclip
10
12
  class Attachment
11
13
  def self.default_options
12
14
  @default_options ||= {
13
- convert_options: {},
14
- default_style: :original,
15
- default_url: "/:attachment/:style/missing.png",
16
- escape_url: true,
17
- restricted_characters: /[&$+,\/:;=?@<>\[\]\{\}\|\\\^~%# ]/,
18
- filename_cleaner: nil,
19
- hash_data: ":class/:attachment/:id/:style/:updated_at",
20
- hash_digest: "SHA1",
21
- interpolator: Paperclip::Interpolations,
22
- only_process: [],
23
- path: ":rails_root/public:url",
24
- preserve_files: false,
25
- processors: [:thumbnail],
26
- source_file_options: {},
27
- storage: :filesystem,
28
- styles: {},
29
- url: "/system/:class/:attachment/:id_partition/:style/:filename",
30
- url_generator: Paperclip::UrlGenerator,
31
- use_default_time_zone: true,
32
- use_timestamp: true,
33
- whiny: Paperclip.options[:whiny] || Paperclip.options[:whiny_thumbnails],
34
- validate_media_type: true,
35
- adapter_options: { hash_digest: Digest::MD5 },
36
- check_validity_before_processing: true
15
+ convert_options: {},
16
+ default_style: :original,
17
+ default_url: "/:attachment/:style/missing.png",
18
+ escape_url: true,
19
+ restricted_characters: /[&$+,\/:;=?@<>\[\]\{\}\|\\\^~%# ]/,
20
+ filename_cleaner: nil,
21
+ hash_data: ":class/:attachment/:id/:style/:updated_at",
22
+ hash_digest: "SHA1",
23
+ interpolator: Paperclip::Interpolations,
24
+ only_process: [],
25
+ path: ":rails_root/public:url",
26
+ preserve_files: false,
27
+ processors: [:thumbnail],
28
+ source_file_options: {},
29
+ storage: :filesystem,
30
+ styles: {},
31
+ url: "/system/:class/:attachment/:id_partition/:style/:filename",
32
+ url_generator: Paperclip::UrlGenerator,
33
+ use_default_time_zone: true,
34
+ use_timestamp: true,
35
+ whiny: Paperclip.options[:whiny] || Paperclip.options[:whiny_thumbnails],
36
+ validate_media_type: true,
37
+ adapter_options: { hash_digest: Digest::MD5 },
38
+ check_validity_before_processing: true,
39
+ return_file_attributes_on_destroy: false
37
40
  }
38
41
  end
39
42
 
@@ -69,6 +72,8 @@ module Paperclip
69
72
  # +interpolator+ - the object used to interpolate filenames and URLs. Defaults to Paperclip::Interpolations
70
73
  # +url_generator+ - the object used to generate URLs, using the interpolator. Defaults to Paperclip::UrlGenerator
71
74
  # +escape_url+ - Perform URI escaping to URLs. Defaults to true
75
+ # +return_file_attributes_on_destroy+ - whether attachment-related attributes should be displayed when
76
+ # destroying a record. Defaults to false.
72
77
  def initialize(name, instance, options = {})
73
78
  @name = name.to_sym
74
79
  @name_string = name.to_s
@@ -563,12 +568,10 @@ module Paperclip
563
568
  path(style) if exists?(style)
564
569
  end.compact
565
570
  end
566
- instance_write(:file_name, nil)
567
- instance_write(:content_type, nil)
568
- instance_write(:file_size, nil)
569
- instance_write(:fingerprint, nil)
570
- instance_write(:created_at, nil) if has_enabled_but_unset_created_at?
571
- instance_write(:updated_at, nil)
571
+
572
+ return if show_attrs_and_destroy_callback_triggered?
573
+
574
+ clear_all_attachment_attributes
572
575
  end
573
576
 
574
577
  def flush_errors #:nodoc:
@@ -613,5 +616,21 @@ module Paperclip
613
616
  def has_enabled_but_unset_created_at?
614
617
  able_to_store_created_at? && !instance_read(:created_at)
615
618
  end
619
+
620
+ # Checks whether the option to show attributes to be destroyed is enabled and whether a destroy callback has been
621
+ # invoked when deleting the entire record.
622
+ def show_attrs_and_destroy_callback_triggered?
623
+ @options[:return_file_attributes_on_destroy] && instance.instance_variable_get(:@_destroy_callback_already_called)
624
+ end
625
+
626
+ # Sets attachment-related attributes to `nil`.
627
+ def clear_all_attachment_attributes
628
+ instance_write(:file_name, nil)
629
+ instance_write(:content_type, nil)
630
+ instance_write(:file_size, nil)
631
+ instance_write(:fingerprint, nil)
632
+ instance_write(:created_at, nil) if has_enabled_but_unset_created_at?
633
+ instance_write(:updated_at, nil)
634
+ end
616
635
  end
617
636
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "singleton"
2
4
 
3
5
  module Paperclip
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Paperclip
2
4
  module Callbacks
3
5
  def self.included(base)
@@ -9,14 +11,15 @@ module Paperclip
9
11
  def define_paperclip_callbacks(*callbacks)
10
12
  define_callbacks(*[callbacks, { terminator: hasta_la_vista_baby }].flatten)
11
13
  callbacks.each do |callback|
12
- eval <<-end_callbacks
13
- def before_#{callback}(*args, &blk)
14
+ class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
15
+ def self.before_#{callback}(*args, &blk)
14
16
  set_callback(:#{callback}, :before, *args, &blk)
15
17
  end
16
- def after_#{callback}(*args, &blk)
18
+
19
+ def self.after_#{callback}(*args, &blk)
17
20
  set_callback(:#{callback}, :after, *args, &blk)
18
21
  end
19
- end_callbacks
22
+ RUBY
20
23
  end
21
24
  end
22
25
 
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Paperclip
4
+ module Commands
5
+ module ImageMagick
6
+ module GeometryParser
7
+ extend self
8
+
9
+ FORMAT = /\b(\d*)x?(\d*)\b(?:,(\d?))?(@>|>@|[><#@%^!])?/i.freeze
10
+
11
+ # Runs `magick identify` and returns a Paperclip::Geometry
12
+ def detect(file)
13
+ parse(fetch(file))
14
+ end
15
+ alias_method :from_file, :detect
16
+
17
+ # Parses a "WxH,O" string into a Paperclip::Geometry
18
+ def parse(string)
19
+ return unless (match = string&.strip&.match(FORMAT))
20
+
21
+ Paperclip::Geometry.new(
22
+ width: match[1],
23
+ height: match[2],
24
+ orientation: match[3],
25
+ modifier: match[4]
26
+ )
27
+ end
28
+
29
+ private
30
+
31
+ def fetch(file)
32
+ filepath = path(file)
33
+ raise_error("Cannot find the geometry of a file with a blank name") if filepath.blank?
34
+
35
+ str = Paperclip::Commands::ImageMagick.identify(
36
+ "-format '%wx%h,#{orientation}' :file",
37
+ { file: "#{filepath}[0]" },
38
+ { swallow_stderr: true }
39
+ ).presence
40
+
41
+ raise_error unless str
42
+
43
+ str
44
+ rescue Terrapin::ExitStatusError
45
+ raise_error
46
+ end
47
+
48
+ def path(file)
49
+ file.respond_to?(:path) ? file.path : file
50
+ end
51
+
52
+ def orientation
53
+ Paperclip.options[:use_exif_orientation] ? "%[exif:orientation]" : "1"
54
+ end
55
+
56
+ def raise_error(message = nil)
57
+ message ||= "Could not identify image size"
58
+ raise Errors::NotIdentifiedByImageMagickError.new(message)
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Paperclip
4
+ module Commands
5
+ module ImageMagick
6
+ module VersionDetector
7
+ extend self
8
+
9
+ # Returns 6, 7, or nil (not installed)
10
+ def detected_version
11
+ return @detected_version if defined?(@detected_version)
12
+
13
+ @detected_version = detect
14
+ end
15
+
16
+ private
17
+
18
+ def detect
19
+ return 7 if valid?("magick")
20
+ return 6 if valid?("convert")
21
+
22
+ nil
23
+ end
24
+
25
+ def valid?(command)
26
+ run(command).to_s.include?("ImageMagick")
27
+ end
28
+
29
+ def run(command)
30
+ Paperclip::Commands::Runner.run(command, path, "-version", {}, swallow_stderr: true)
31
+ rescue Terrapin::CommandLineError
32
+ nil
33
+ end
34
+
35
+ def path
36
+ Paperclip::Commands::ImageMagick.imagemagick_path
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Paperclip
4
+ module Commands
5
+ module ImageMagick
6
+ extend self
7
+
8
+ def convert(arguments = nil, interpolation_values = {}, local_options = {})
9
+ run(convert_command, imagemagick_path, arguments, interpolation_values, local_options)
10
+ end
11
+
12
+ def identify(arguments = nil, interpolation_values = {}, local_options = {})
13
+ run(identify_command, imagemagick_path, arguments, interpolation_values, local_options)
14
+ end
15
+
16
+ def imagemagick_path
17
+ Paperclip.options[:imagemagick_path]
18
+ end
19
+
20
+ private
21
+
22
+ def run(command, path = nil, arguments = nil, interpolation_values = {}, local_options = {})
23
+ Runner.run(command, path || imagemagick_path, arguments, interpolation_values, local_options)
24
+ rescue Terrapin::CommandNotFoundError
25
+ raise Errors::CommandNotFoundError.new("Could not run the `#{command}` command. Please install ImageMagick.")
26
+ end
27
+
28
+ # Returns true if ImageMagick 7 is in use (either detected or forced via config)
29
+ def magick_command?
30
+ version = Paperclip.options[:imagemagick_version]&.to_i ||
31
+ VersionDetector.detected_version
32
+ !version.nil? && version >= 7
33
+ end
34
+
35
+ def convert_command
36
+ magick_command? ? "magick" : "convert"
37
+ end
38
+
39
+ def identify_command
40
+ magick_command? ? "magick identify" : "identify"
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Paperclip
4
+ module Commands
5
+ module Runner
6
+ extend self
7
+
8
+ def run(command, path = nil, arguments = nil, interpolation_values = {}, local_options = {})
9
+ if Paperclip.logging? && (Paperclip.options[:log_command] || local_options[:log_command])
10
+ local_options = local_options.merge(logger: Paperclip.logger)
11
+ end
12
+
13
+ binary = resolve_binary(command, path)
14
+
15
+ Terrapin::CommandLine.new(binary, arguments, local_options)
16
+ .run(interpolation_values)
17
+ end
18
+
19
+ private
20
+
21
+ def resolve_binary(command, path)
22
+ # @deprecated +Paperclip.options[:command_path]+ will be removed in Paperclip 8.0
23
+ path ||= Paperclip.options[:command_path]
24
+ return command unless path
25
+
26
+ # command may be multi-word (e.g. "magick identify")
27
+ words = command.split(" ", 2)
28
+ candidate = File.join(path, words[0])
29
+ if File.executable?(candidate)
30
+ words[0] = candidate
31
+ words.join(" ")
32
+ else
33
+ command
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Paperclip
4
+ module Commands
5
+ module UnixFile
6
+ extend self
7
+
8
+ # Returns a normalized content type value, otherwise nil.
9
+ def detect_content_type(file)
10
+ type = run_file_command(file)
11
+ return if type.blank? || type.match(/\(.*?\)/)
12
+
13
+ type.split(/[:;\s]+/)[0].strip
14
+ rescue Terrapin::CommandLineError => e
15
+ Paperclip.log("Error while determining content type: #{e}")
16
+ nil
17
+ end
18
+
19
+ private
20
+
21
+ def run_file_command(file)
22
+ Runner.run("file", Paperclip.options[:file_command_path], "-b --mime :file", { file: file })
23
+ rescue Terrapin::CommandLineError
24
+ nil
25
+ end
26
+ end
27
+ end
28
+ end
@@ -1,22 +1,25 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Paperclip
4
+ # The content-type detection strategy is as follows:
5
+ #
6
+ # 1. Blank/Empty files: If there's no filepath or the file is empty,
7
+ # provide a sensible default (application/octet-stream or inode/x-empty)
8
+ #
9
+ # 2. Calculated match: Return the first result that is found by both the
10
+ # Marcel gem (or `file` command) and MIME::Types.
11
+ #
12
+ # 3. Standard types: Return the first standard (without an x- prefix) entry
13
+ # in MIME::Types
14
+ #
15
+ # 4. Experimental types: If there were no standard types in MIME::Types
16
+ # list, try to return the first experimental one
17
+ #
18
+ # 5. Raw `file` command: Just use the output of Marcel (or `file` command),
19
+ # cached from step 2.
20
+ #
21
+ # 6. If nothing found, return a sensible default.
2
22
  class ContentTypeDetector
3
- # The content-type detection strategy is as follows:
4
- #
5
- # 1. Blank/Empty files: If there's no filepath or the file is empty,
6
- # provide a sensible default (application/octet-stream or inode/x-empty)
7
- #
8
- # 2. Calculated match: Return the first result that is found by both the
9
- # `file` command and MIME::Types.
10
- #
11
- # 3. Standard types: Return the first standard (without an x- prefix) entry
12
- # in MIME::Types
13
- #
14
- # 4. Experimental types: If there were no standard types in MIME::Types
15
- # list, try to return the first experimental one
16
- #
17
- # 5. Raw `file` command: Just use the output of the `file` command raw, or
18
- # a sensible default. This is cached from Step 2.
19
-
20
23
  EMPTY_TYPE = "inode/x-empty"
21
24
  SENSIBLE_DEFAULT = "application/octet-stream"
22
25
 
@@ -25,15 +28,15 @@ module Paperclip
25
28
  end
26
29
 
27
30
  # Returns a String describing the file's content type
28
- def detect
31
+ def detect(default = SENSIBLE_DEFAULT)
29
32
  if blank_name?
30
- SENSIBLE_DEFAULT
33
+ default
31
34
  elsif empty_file?
32
35
  EMPTY_TYPE
33
36
  elsif calculated_type_matches.any?
34
37
  calculated_type_matches.first
35
38
  else
36
- type_from_file_contents || SENSIBLE_DEFAULT
39
+ type_from_file_contents || default
37
40
  end.to_s
38
41
  end
39
42
 
@@ -60,26 +63,22 @@ module Paperclip
60
63
  end
61
64
 
62
65
  def type_from_file_contents
63
- type_from_marcel || type_from_file_command
66
+ return @type_from_file_contents if defined?(@type_from_file_contents)
67
+
68
+ @type_from_file_contents = type_from_marcel || type_from_file_command
64
69
  rescue Errno::ENOENT => e
65
70
  Paperclip.log("Error while determining content type: #{e}")
66
- SENSIBLE_DEFAULT
71
+ @type_from_file_contents = nil
67
72
  end
68
73
 
69
74
  def type_from_marcel
70
- return @type_from_marcel if defined? @type_from_marcel
71
-
72
- @type_from_marcel = Marcel::MimeType.for Pathname.new(@filepath),
73
- name: @filepath
74
- # Marcel::MineType returns 'application/octet-stream' if it can't find
75
- # a valid type.
76
- @type_from_marcel = nil if @type_from_marcel == SENSIBLE_DEFAULT
77
- @type_from_marcel
75
+ type = Marcel::MimeType.for(Pathname.new(@filepath), name: @filepath)
76
+ # Marcel::MineType returns 'application/octet-stream' if it can't find a valid type.
77
+ type == SENSIBLE_DEFAULT ? nil : type
78
78
  end
79
79
 
80
80
  def type_from_file_command
81
- @type_from_file_command ||=
82
- FileCommandContentTypeDetector.new(@filepath).detect
81
+ Commands::UnixFile.detect_content_type(@filepath)
83
82
  end
84
83
  end
85
84
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Paperclip
2
4
  # A base error class for Paperclip. Most of the error that will be thrown
3
5
  # from Paperclip will inherits from this class.
@@ -1,28 +1,27 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Paperclip
4
+ # @deprecated Will be removed in Paperclip 8.0. Use +Paperclip::ContentTypeDetector+ instead.
2
5
  class FileCommandContentTypeDetector
6
+ # @deprecated Will be removed in Paperclip 8.0.
3
7
  SENSIBLE_DEFAULT = "application/octet-stream"
4
8
 
9
+ # @deprecated Will be removed in Paperclip 8.0. Use +Paperclip::ContentTypeDetector+ instead.
5
10
  def initialize(filename)
11
+ warn_deprecation
6
12
  @filename = filename
7
13
  end
8
14
 
15
+ # @deprecated Will be removed in Paperclip 8.0. Use +Paperclip::ContentTypeDetector+ instead.
9
16
  def detect
10
- type_from_file_command
17
+ warn_deprecation
18
+ Paperclip::Commands::UnixFile.detect_content_type(@filename) || SENSIBLE_DEFAULT
11
19
  end
12
20
 
13
21
  private
14
22
 
15
- def type_from_file_command
16
- # On BSDs, `file` doesn't give a result code of 1 if the file doesn't exist.
17
- type = begin
18
- Paperclip.run("file", "-b --mime :file", file: @filename)
19
- rescue Terrapin::CommandLineError => e
20
- Paperclip.log("Error while determining content type: #{e}")
21
- SENSIBLE_DEFAULT
22
- end
23
-
24
- type = SENSIBLE_DEFAULT if type.nil? || type.match(/\(.*?\)/)
25
- type.split(/[:;\s]+/)[0]
23
+ def warn_deprecation
24
+ Paperclip.deprecator.warn("Paperclip::FileCommandContentTypeDetector has been replaced by Paperclip::ContentTypeDetector.")
26
25
  end
27
26
  end
28
27
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Paperclip
2
4
  class FilenameCleaner
3
5
  def initialize(invalid_character_regex)