shrine 2.19.4 → 3.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (209) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +485 -43
  3. data/LICENSE.txt +1 -1
  4. data/README.md +81 -977
  5. data/doc/advantages.md +231 -204
  6. data/doc/attacher.md +304 -153
  7. data/doc/carrierwave.md +297 -226
  8. data/doc/changing_derivatives.md +308 -0
  9. data/doc/changing_location.md +102 -21
  10. data/doc/changing_storage.md +110 -0
  11. data/doc/creating_persistence_plugins.md +132 -0
  12. data/doc/creating_plugins.md +43 -23
  13. data/doc/creating_storages.md +19 -5
  14. data/doc/design.md +147 -97
  15. data/doc/direct_s3.md +38 -28
  16. data/doc/external/articles.md +63 -0
  17. data/doc/external/extensions.md +53 -0
  18. data/doc/external/misc.md +32 -0
  19. data/doc/getting_started.md +1115 -0
  20. data/doc/metadata.md +190 -109
  21. data/doc/multiple_files.md +62 -34
  22. data/doc/paperclip.md +384 -262
  23. data/doc/plugins/activerecord.md +177 -46
  24. data/doc/plugins/add_metadata.md +139 -38
  25. data/doc/plugins/atomic_helpers.md +217 -0
  26. data/doc/plugins/backgrounding.md +156 -98
  27. data/doc/plugins/cached_attachment_data.md +7 -5
  28. data/doc/plugins/column.md +121 -0
  29. data/doc/plugins/data_uri.md +23 -22
  30. data/doc/plugins/default_storage.md +36 -10
  31. data/doc/plugins/default_url.md +30 -13
  32. data/doc/plugins/delete_raw.md +4 -2
  33. data/doc/plugins/derivation_endpoint.md +162 -101
  34. data/doc/plugins/derivatives.md +829 -0
  35. data/doc/plugins/determine_mime_type.md +4 -2
  36. data/doc/plugins/download_endpoint.md +64 -8
  37. data/doc/plugins/dynamic_storage.md +5 -3
  38. data/doc/plugins/entity.md +263 -0
  39. data/doc/plugins/form_assign.md +55 -0
  40. data/doc/plugins/included.md +31 -8
  41. data/doc/plugins/infer_extension.md +21 -10
  42. data/doc/plugins/instrumentation.md +38 -16
  43. data/doc/plugins/keep_files.md +14 -17
  44. data/doc/plugins/metadata_attributes.md +42 -13
  45. data/doc/plugins/mirroring.md +118 -0
  46. data/doc/plugins/model.md +210 -0
  47. data/doc/plugins/module_include.md +4 -2
  48. data/doc/plugins/multi_cache.md +24 -0
  49. data/doc/plugins/persistence.md +101 -0
  50. data/doc/plugins/presign_endpoint.md +9 -4
  51. data/doc/plugins/pretty_location.md +16 -3
  52. data/doc/plugins/processing.md +4 -2
  53. data/doc/plugins/rack_file.md +8 -2
  54. data/doc/plugins/rack_response.md +6 -2
  55. data/doc/plugins/recache.md +4 -2
  56. data/doc/plugins/refresh_metadata.md +49 -9
  57. data/doc/plugins/remote_url.md +84 -47
  58. data/doc/plugins/remove_attachment.md +27 -6
  59. data/doc/plugins/remove_invalid.md +21 -6
  60. data/doc/plugins/restore_cached_data.md +11 -3
  61. data/doc/plugins/sequel.md +159 -35
  62. data/doc/plugins/signature.md +16 -5
  63. data/doc/plugins/store_dimensions.md +14 -2
  64. data/doc/plugins/tempfile.md +4 -2
  65. data/doc/plugins/type_predicates.md +96 -0
  66. data/doc/plugins/upload_endpoint.md +13 -13
  67. data/doc/plugins/upload_options.md +6 -4
  68. data/doc/plugins/{default_url_options.md → url_options.md} +9 -7
  69. data/doc/plugins/validation.md +97 -0
  70. data/doc/plugins/validation_helpers.md +16 -13
  71. data/doc/plugins/versions.md +15 -19
  72. data/doc/processing.md +438 -221
  73. data/doc/refile.md +185 -167
  74. data/doc/release_notes/1.0.0.md +4 -0
  75. data/doc/release_notes/1.1.0.md +6 -2
  76. data/doc/release_notes/1.2.0.md +4 -0
  77. data/doc/release_notes/1.3.0.md +4 -0
  78. data/doc/release_notes/1.4.0.md +4 -0
  79. data/doc/release_notes/1.4.1.md +4 -0
  80. data/doc/release_notes/1.4.2.md +4 -0
  81. data/doc/release_notes/2.0.0.md +4 -0
  82. data/doc/release_notes/2.0.1.md +4 -0
  83. data/doc/release_notes/2.1.0.md +4 -0
  84. data/doc/release_notes/2.1.1.md +4 -0
  85. data/doc/release_notes/2.10.0.md +4 -0
  86. data/doc/release_notes/2.10.1.md +4 -0
  87. data/doc/release_notes/2.11.0.md +4 -0
  88. data/doc/release_notes/2.12.0.md +4 -0
  89. data/doc/release_notes/2.13.0.md +4 -0
  90. data/doc/release_notes/2.14.0.md +5 -1
  91. data/doc/release_notes/2.15.0.md +11 -7
  92. data/doc/release_notes/2.16.0.md +4 -0
  93. data/doc/release_notes/2.17.0.md +4 -0
  94. data/doc/release_notes/2.18.0.md +4 -0
  95. data/doc/release_notes/2.19.0.md +6 -3
  96. data/doc/release_notes/2.2.0.md +4 -0
  97. data/doc/release_notes/2.3.0.md +4 -0
  98. data/doc/release_notes/2.3.1.md +4 -0
  99. data/doc/release_notes/2.4.0.md +4 -0
  100. data/doc/release_notes/2.4.1.md +4 -0
  101. data/doc/release_notes/2.5.0.md +4 -0
  102. data/doc/release_notes/2.6.0.md +4 -0
  103. data/doc/release_notes/2.6.1.md +4 -0
  104. data/doc/release_notes/2.7.0.md +4 -0
  105. data/doc/release_notes/2.8.0.md +4 -0
  106. data/doc/release_notes/2.9.0.md +4 -0
  107. data/doc/release_notes/3.0.0.md +981 -0
  108. data/doc/release_notes/3.0.1.md +22 -0
  109. data/doc/release_notes/3.1.0.md +73 -0
  110. data/doc/release_notes/3.2.0.md +96 -0
  111. data/doc/release_notes/3.2.1.md +31 -0
  112. data/doc/release_notes/3.2.2.md +14 -0
  113. data/doc/release_notes/3.3.0.md +105 -0
  114. data/doc/release_notes/3.4.0.md +35 -0
  115. data/doc/retrieving_uploads.md +4 -1
  116. data/doc/securing_uploads.md +60 -37
  117. data/doc/storage/file_system.md +20 -3
  118. data/doc/storage/memory.md +19 -0
  119. data/doc/storage/s3.md +117 -83
  120. data/doc/testing.md +124 -144
  121. data/doc/upgrading_to_3.md +710 -0
  122. data/doc/validation.md +54 -90
  123. data/lib/shrine/attacher.rb +287 -171
  124. data/lib/shrine/attachment.rb +13 -46
  125. data/lib/shrine/plugins/_persistence.rb +93 -0
  126. data/lib/shrine/plugins/activerecord.rb +77 -34
  127. data/lib/shrine/plugins/add_metadata.rb +25 -17
  128. data/lib/shrine/plugins/atomic_helpers.rb +119 -0
  129. data/lib/shrine/plugins/backgrounding.rb +77 -113
  130. data/lib/shrine/plugins/cached_attachment_data.rb +6 -15
  131. data/lib/shrine/plugins/column.rb +102 -0
  132. data/lib/shrine/plugins/data_uri.rb +38 -36
  133. data/lib/shrine/plugins/default_storage.rb +45 -15
  134. data/lib/shrine/plugins/default_url.rb +12 -24
  135. data/lib/shrine/plugins/default_url_options.rb +3 -30
  136. data/lib/shrine/plugins/delete_raw.rb +10 -16
  137. data/lib/shrine/plugins/derivation_endpoint.rb +89 -134
  138. data/lib/shrine/plugins/derivatives.rb +637 -0
  139. data/lib/shrine/plugins/determine_mime_type.rb +9 -21
  140. data/lib/shrine/plugins/download_endpoint.rb +109 -133
  141. data/lib/shrine/plugins/dynamic_storage.rb +5 -11
  142. data/lib/shrine/plugins/entity.rb +152 -0
  143. data/lib/shrine/plugins/form_assign.rb +108 -0
  144. data/lib/shrine/plugins/included.rb +6 -6
  145. data/lib/shrine/plugins/infer_extension.rb +13 -20
  146. data/lib/shrine/plugins/instrumentation.rb +54 -42
  147. data/lib/shrine/plugins/keep_files.rb +3 -15
  148. data/lib/shrine/plugins/metadata_attributes.rb +28 -19
  149. data/lib/shrine/plugins/mirroring.rb +142 -0
  150. data/lib/shrine/plugins/model.rb +158 -0
  151. data/lib/shrine/plugins/module_include.rb +3 -3
  152. data/lib/shrine/plugins/multi_cache.rb +27 -0
  153. data/lib/shrine/plugins/presign_endpoint.rb +18 -22
  154. data/lib/shrine/plugins/pretty_location.rb +15 -9
  155. data/lib/shrine/plugins/processing.rb +22 -9
  156. data/lib/shrine/plugins/rack_file.rb +2 -42
  157. data/lib/shrine/plugins/rack_response.rb +15 -10
  158. data/lib/shrine/plugins/recache.rb +6 -5
  159. data/lib/shrine/plugins/refresh_metadata.rb +13 -11
  160. data/lib/shrine/plugins/remote_url.rb +49 -49
  161. data/lib/shrine/plugins/remove_attachment.rb +10 -6
  162. data/lib/shrine/plugins/remove_invalid.rb +19 -8
  163. data/lib/shrine/plugins/restore_cached_data.rb +13 -7
  164. data/lib/shrine/plugins/sequel.rb +86 -36
  165. data/lib/shrine/plugins/signature.rb +10 -16
  166. data/lib/shrine/plugins/store_dimensions.rb +35 -40
  167. data/lib/shrine/plugins/tempfile.rb +1 -3
  168. data/lib/shrine/plugins/type_predicates.rb +113 -0
  169. data/lib/shrine/plugins/upload_endpoint.rb +25 -23
  170. data/lib/shrine/plugins/upload_options.rb +14 -15
  171. data/lib/shrine/plugins/url_options.rb +31 -0
  172. data/lib/shrine/plugins/validation.rb +80 -0
  173. data/lib/shrine/plugins/validation_helpers.rb +34 -57
  174. data/lib/shrine/plugins/versions.rb +107 -87
  175. data/lib/shrine/plugins.rb +22 -0
  176. data/lib/shrine/storage/file_system.rb +46 -64
  177. data/lib/shrine/storage/linter.rb +42 -7
  178. data/lib/shrine/storage/memory.rb +49 -0
  179. data/lib/shrine/storage/s3.rb +154 -158
  180. data/lib/shrine/uploaded_file.rb +28 -30
  181. data/lib/shrine/version.rb +3 -3
  182. data/lib/shrine.rb +86 -149
  183. data/shrine.gemspec +9 -10
  184. metadata +79 -83
  185. data/doc/migrating_storage.md +0 -76
  186. data/doc/plugins/backup.md +0 -31
  187. data/doc/plugins/copy.md +0 -24
  188. data/doc/plugins/delete_promoted.md +0 -12
  189. data/doc/plugins/direct_upload.md +0 -172
  190. data/doc/plugins/hooks.md +0 -58
  191. data/doc/plugins/logging.md +0 -42
  192. data/doc/plugins/migration_helpers.md +0 -60
  193. data/doc/plugins/moving.md +0 -19
  194. data/doc/plugins/multi_delete.md +0 -20
  195. data/doc/plugins/parallelize.md +0 -16
  196. data/doc/plugins/parsed_json.md +0 -23
  197. data/doc/regenerating_versions.md +0 -143
  198. data/lib/shrine/plugins/background_helpers.rb +0 -5
  199. data/lib/shrine/plugins/backup.rb +0 -90
  200. data/lib/shrine/plugins/copy.rb +0 -50
  201. data/lib/shrine/plugins/delete_promoted.rb +0 -20
  202. data/lib/shrine/plugins/direct_upload.rb +0 -217
  203. data/lib/shrine/plugins/hooks.rb +0 -90
  204. data/lib/shrine/plugins/logging.rb +0 -142
  205. data/lib/shrine/plugins/migration_helpers.rb +0 -70
  206. data/lib/shrine/plugins/moving.rb +0 -57
  207. data/lib/shrine/plugins/multi_delete.rb +0 -32
  208. data/lib/shrine/plugins/parallelize.rb +0 -78
  209. data/lib/shrine/plugins/parsed_json.rb +0 -29
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- Shrine.deprecation("The copy plugin is deprecated and will be removed in Shrine 3.")
4
-
5
- class Shrine
6
- module Plugins
7
- # Documentation lives in [doc/plugins/copy.md] on GitHub.
8
- #
9
- # [doc/plugins/copy.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/copy.md
10
- module Copy
11
- module AttachmentMethods
12
- def initialize(*)
13
- super
14
-
15
- name = attachment_name
16
-
17
- define_method :initialize_copy do |record|
18
- super(record)
19
- instance_variable_set(:"@#{name}_attacher", nil) # reload the attacher
20
- attacher = send(:"#{name}_attacher")
21
- attacher.send(:write, nil) # remove original attachment
22
- attacher.copy(record.public_send(:"#{name}_attacher"))
23
- end
24
-
25
- # Fix for JRuby
26
- private :initialize_copy
27
- end
28
- end
29
-
30
- module AttacherMethods
31
- def copy(attacher)
32
- options = {action: :copy, move: false}
33
-
34
- copied_attachment = if attacher.cached?
35
- cache!(attacher.get, **options)
36
- elsif attacher.stored?
37
- store!(attacher.get, **options)
38
- else
39
- nil
40
- end
41
-
42
- @old = get
43
- _set(copied_attachment)
44
- end
45
- end
46
- end
47
-
48
- register_plugin(:copy, Copy)
49
- end
50
- end
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Shrine
4
- module Plugins
5
- # Documentation lives in [doc/plugins/delete_promoted.md] on GitHub.
6
- #
7
- # [doc/plugins/delete_promoted.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/delete_promoted.md
8
- module DeletePromoted
9
- module AttacherMethods
10
- def promote(uploaded_file = get, **options)
11
- result = super
12
- _delete(uploaded_file, action: :promote)
13
- result
14
- end
15
- end
16
- end
17
-
18
- register_plugin(:delete_promoted, DeletePromoted)
19
- end
20
- end
@@ -1,217 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- Shrine.deprecation("The direct_upload plugin has been deprecated in favor of upload_endpoint and presign_endpoint plugins. The direct_upload plugin will be removed in Shrine 3.")
4
-
5
- require "roda"
6
- require "json"
7
-
8
- class Shrine
9
- module Plugins
10
- # Documentation lives in [doc/plugins/direct_upload.md] on GitHub.
11
- #
12
- # [doc/plugins/direct_upload.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/direct_upload.md
13
- module DirectUpload
14
- def self.load_dependencies(uploader, *)
15
- uploader.plugin :rack_file
16
- end
17
-
18
- def self.configure(uploader, opts = {})
19
- uploader.opts[:direct_upload_allowed_storages] = opts.fetch(:allowed_storages, uploader.opts.fetch(:direct_upload_allowed_storages, [:cache]))
20
- uploader.opts[:direct_upload_presign_options] = opts.fetch(:presign_options, uploader.opts.fetch(:direct_upload_presign_options, {}))
21
- uploader.opts[:direct_upload_presign_location] = opts.fetch(:presign_location, uploader.opts[:direct_upload_presign_location])
22
- uploader.opts[:direct_upload_max_size] = opts.fetch(:max_size, uploader.opts[:direct_upload_max_size])
23
-
24
- uploader.assign_upload_endpoint(App) unless uploader.const_defined?(:UploadEndpoint)
25
- end
26
-
27
- module ClassMethods
28
- # Assigns the subclass a copy of the upload endpoint class.
29
- def inherited(subclass)
30
- super
31
- subclass.assign_upload_endpoint(self::UploadEndpoint)
32
- end
33
-
34
- # Assigns the subclassed endpoint as the `UploadEndpoint` constant.
35
- def assign_upload_endpoint(klass)
36
- endpoint_class = Class.new(klass)
37
- endpoint_class.opts[:shrine_class] = self
38
- const_set(:UploadEndpoint, endpoint_class)
39
- end
40
- end
41
-
42
- # Routes incoming requests. It first asserts that the storage is existent
43
- # and allowed, then the filesize isn't too large. Afterwards it proceeds
44
- # with the file upload and returns the uploaded file as JSON.
45
- class App < Roda
46
- plugin :default_headers, "Content-Type"=>"application/json"
47
- plugin :placeholder_string_matchers if Gem::Version.new(Roda::RodaVersion) >= Gem::Version.new("3.0.0")
48
-
49
- route do |r|
50
- r.on ":storage" do |storage_key|
51
- @uploader = get_uploader(storage_key)
52
-
53
- r.post ["upload", ":name"] do |name|
54
- file = get_file
55
- context = get_context(name)
56
-
57
- uploaded_file = upload(file, context)
58
-
59
- json uploaded_file
60
- end
61
-
62
- r.get "presign" do
63
- location = get_presign_location
64
- options = get_presign_options
65
-
66
- presign_data = generate_presign(location, options)
67
- response.headers["Cache-Control"] = "no-store"
68
-
69
- json presign_data
70
- end
71
- end
72
- end
73
-
74
- private
75
-
76
- attr_reader :uploader
77
-
78
- # Instantiates the uploader, checking first if the storage is allowed.
79
- def get_uploader(storage_key)
80
- allow_storage!(storage_key)
81
- shrine_class.new(storage_key.to_sym)
82
- end
83
-
84
- # Retrieves the context for the upload.
85
- def get_context(name)
86
- context = {action: :cache, phase: :cache}
87
-
88
- if name != "upload"
89
- Shrine.deprecation("The \"POST /:storage/:name\" route of the direct_upload plugin is deprecated, and it will be removed in Shrine 3. Use \"POST /:storage/upload\" instead.")
90
- context[:name] = name
91
- end
92
-
93
- unless presign_storage?
94
- context[:location] = request.params["key"]
95
- end
96
-
97
- context
98
- end
99
-
100
- # Uploads the file to the requested storage.
101
- def upload(file, context)
102
- uploader.upload(file, context)
103
- end
104
-
105
- # Generates a unique location, or calls `:presign_location`.
106
- def get_presign_location
107
- if presign_location
108
- presign_location.call(request)
109
- else
110
- extension = request.params["extension"]
111
- extension.prepend(".") if extension && !extension.start_with?(".")
112
- uploader.send(:generate_uid, nil) + extension.to_s
113
- end
114
- end
115
-
116
- # Returns dynamic options for generating the presign.
117
- def get_presign_options
118
- options = presign_options
119
- options = options.call(request) if options.respond_to?(:call)
120
- options || {}
121
- end
122
-
123
- # Generates the presign hash for the request.
124
- def generate_presign(location, options)
125
- if presign_storage?
126
- generate_real_presign(location, options)
127
- else
128
- generate_fake_presign(location, options)
129
- end
130
- end
131
-
132
- # Generates a presign by calling the storage.
133
- def generate_real_presign(location, options)
134
- signature = uploader.storage.presign(location, options)
135
- {url: signature.url, fields: signature.fields}
136
- end
137
-
138
- # Generates a presign that points to the direct upload endpoint.
139
- def generate_fake_presign(location, options)
140
- url = request.url.sub(/presign[^\/]*$/, "upload")
141
- {url: url, fields: {key: location}}
142
- end
143
-
144
- # Returns true if the storage supports presigns.
145
- def presign_storage?
146
- uploader.storage.respond_to?(:presign)
147
- end
148
-
149
- # Halts the request if storage is not allowed.
150
- def allow_storage!(storage_key)
151
- if !allowed_storages.map(&:to_s).include?(storage_key)
152
- error! 403, "Storage #{storage_key.inspect} is not allowed."
153
- end
154
- end
155
-
156
- # Returns the Rack file wrapped in an IO-like object. If "file" is
157
- # missing or is too big, the request is halted.
158
- def get_file
159
- file = require_param!("file")
160
- error! 400, "The \"file\" query parameter is not a file." if !(file.is_a?(Hash) && file.key?(:tempfile))
161
- check_filesize!(file[:tempfile]) if max_size
162
-
163
- RackFile::UploadedFile.new(file)
164
- end
165
-
166
- # If the file is too big, deletes the file and halts the request.
167
- def check_filesize!(file)
168
- if file.size > max_size
169
- file.delete
170
- megabytes = max_size.to_f / 1024 / 1024
171
- error! 413, "The file is too big (maximum size is #{megabytes} MB)."
172
- end
173
- end
174
-
175
- # Loudly requires the param.
176
- def require_param!(name)
177
- request.params.fetch(name)
178
- rescue KeyError
179
- error! 400, "Missing query parameter: #{name.inspect}"
180
- end
181
-
182
- # Halts the request with the error message.
183
- def error!(status, message)
184
- response.status = status
185
- response.write({error: message}.to_json)
186
- request.halt
187
- end
188
-
189
- def json(object)
190
- object.to_json
191
- end
192
-
193
- def shrine_class
194
- opts[:shrine_class]
195
- end
196
-
197
- def allowed_storages
198
- shrine_class.opts[:direct_upload_allowed_storages]
199
- end
200
-
201
- def presign_options
202
- shrine_class.opts[:direct_upload_presign_options]
203
- end
204
-
205
- def presign_location
206
- shrine_class.opts[:direct_upload_presign_location]
207
- end
208
-
209
- def max_size
210
- shrine_class.opts[:direct_upload_max_size]
211
- end
212
- end
213
- end
214
-
215
- register_plugin(:direct_upload, DirectUpload)
216
- end
217
- end
@@ -1,90 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Shrine
4
- module Plugins
5
- # Documentation lives in [doc/plugins/hooks.md] on GitHub.
6
- #
7
- # [doc/plugins/hooks.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/hooks.md
8
- module Hooks
9
- module InstanceMethods
10
- def upload(io, context = {})
11
- result = nil
12
- before_upload(io, context)
13
- around_upload(io, context) { result = super }
14
- after_upload(io, context)
15
- result
16
- end
17
-
18
- def around_upload(*args)
19
- yield
20
- end
21
-
22
- def before_upload(*)
23
- end
24
-
25
- def after_upload(*)
26
- end
27
-
28
-
29
- def processed(io, context)
30
- result = nil
31
- before_process(io, context)
32
- around_process(io, context) { result = super }
33
- after_process(io, context)
34
- result
35
- end
36
- private :processed
37
-
38
- def around_process(*args)
39
- yield
40
- end
41
-
42
- def before_process(*)
43
- end
44
-
45
- def after_process(*)
46
- end
47
-
48
-
49
- def store(io, context = {})
50
- result = nil
51
- before_store(io, context)
52
- around_store(io, context) { result = super }
53
- after_store(io, context)
54
- result
55
- end
56
-
57
- def around_store(*args)
58
- yield
59
- end
60
-
61
- def before_store(*)
62
- end
63
-
64
- def after_store(*)
65
- end
66
-
67
-
68
- def delete(io, context = {})
69
- result = nil
70
- before_delete(io, context)
71
- around_delete(io, context) { result = super }
72
- after_delete(io, context)
73
- result
74
- end
75
-
76
- def around_delete(*args)
77
- yield
78
- end
79
-
80
- def before_delete(*)
81
- end
82
-
83
- def after_delete(*)
84
- end
85
- end
86
- end
87
-
88
- register_plugin(:hooks, Hooks)
89
- end
90
- end
@@ -1,142 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- Shrine.deprecation("The logging plugin has been deprecated in favor of instrumentation plugin. The logging plugin will be removed in Shrine 3.")
4
-
5
- require "logger"
6
- require "json"
7
- require "time"
8
-
9
- class Shrine
10
- module Plugins
11
- # Documentation lives in [doc/plugins/logging.md] on GitHub.
12
- #
13
- # [doc/plugins/logging.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/logging.md
14
- module Logging
15
- def self.load_dependencies(uploader, *)
16
- uploader.plugin :hooks
17
- end
18
-
19
- def self.configure(uploader, opts = {})
20
- uploader.opts[:logging_stream] = opts.fetch(:stream, uploader.opts.fetch(:logging_stream, $stdout))
21
- uploader.opts[:logging_logger] = opts.fetch(:logger, uploader.opts.fetch(:logging_logger, uploader.create_logger))
22
- uploader.opts[:logging_format] = opts.fetch(:format, uploader.opts.fetch(:logging_format, :human))
23
-
24
- Shrine.deprecation("The :heroku logging format has been renamed to :logfmt. Using :heroku name will stop being supported in Shrine 3.") if uploader.opts[:logging_format] == :heroku
25
- end
26
-
27
- module ClassMethods
28
- def logger=(logger)
29
- @logger = logger
30
- end
31
-
32
- def logger
33
- @logger ||= opts[:logging_logger]
34
- end
35
-
36
- def create_logger
37
- logger = Logger.new(opts[:logging_stream])
38
- logger.level = Logger::INFO
39
- logger.level = Logger::WARN if ENV["RACK_ENV"] == "test"
40
- logger.formatter = pretty_formatter
41
- logger
42
- end
43
-
44
- # It makes logging preamble simpler than the default logger. Also, it
45
- # doesn't output timestamps if on Heroku.
46
- def pretty_formatter
47
- proc do |severity, time, program_name, message|
48
- output = "#{Process.pid}: #{message}\n".dup
49
- output.prepend "#{time.utc.iso8601(3)} " unless ENV["DYNO"]
50
- output
51
- end
52
- end
53
- end
54
-
55
- module InstanceMethods
56
- def store(io, context = {})
57
- log("store", io, context) { super }
58
- end
59
-
60
- def delete(io, context = {})
61
- log("delete", io, context) { super }
62
- end
63
-
64
- private
65
-
66
- def processed(io, context = {})
67
- log("process", io, context) { super }
68
- end
69
-
70
- # Collects the data and sends it for logging.
71
- def log(action, input, context)
72
- result, duration = benchmark { yield }
73
-
74
- _log(
75
- action: action,
76
- phase: context[:action],
77
- uploader: self.class.to_s,
78
- attachment: context[:name],
79
- record_class: (context[:record].class.to_s if context[:record]),
80
- record_id: (context[:record].id if context[:record].respond_to?(:id)),
81
- files: (action == "process" ? [count(input), count(result)] : count(result)),
82
- duration: ("%.2f" % duration).to_f,
83
- ) unless result.nil?
84
-
85
- result
86
- end
87
-
88
- # Determines format of logging and calls appropriate method.
89
- def _log(data)
90
- message = send("_log_message_#{opts[:logging_format]}", data)
91
- self.class.logger.info(message)
92
- end
93
-
94
- def _log_message_human(data)
95
- components = []
96
- components << "#{data[:action].upcase}"
97
- components[-1] += "[#{data[:phase]}]" if data[:phase]
98
- components << "#{data[:uploader]}"
99
- components[-1] += "[:#{data[:attachment]}]" if data[:attachment]
100
- components << "#{data[:record_class]}" if data[:record_class]
101
- components[-1] += "[#{data[:record_id]}]" if data[:record_id]
102
- components << "#{Array(data[:files]).join("-")} #{"file#{"s" if Array(data[:files]).any?{|n| n > 1}}"}"
103
- components << "(#{data[:duration]}s)"
104
- components.join(" ")
105
- end
106
-
107
- def _log_message_json(data)
108
- data[:files] = Array(data[:files]).join("-")
109
- JSON.generate(data)
110
- end
111
-
112
- def _log_message_logfmt(data)
113
- data[:files] = Array(data[:files]).join("-")
114
- data.map { |key, value| "#{key}=#{value}" }.join(" ")
115
- end
116
- alias _log_message_heroku _log_message_logfmt # deprecated alias
117
-
118
- # We may have one file, a hash of versions, or an array of files or
119
- # hashes.
120
- def count(object)
121
- case object
122
- when Hash
123
- object.count
124
- when Array
125
- object.inject(0) { |sum, o| sum += count(o) }
126
- else
127
- 1
128
- end
129
- end
130
-
131
- def benchmark
132
- start = Time.now
133
- result = yield
134
- finish = Time.now
135
- [result, finish - start]
136
- end
137
- end
138
- end
139
-
140
- register_plugin(:logging, Logging)
141
- end
142
- end
@@ -1,70 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- Shrine.deprecation("The migration_helpers plugin is deprecated and will be removed in Shrine 3. Attacher#cached? and Attacher#stored? have been moved to base.")
4
-
5
- class Shrine
6
- module Plugins
7
- # Documentation lives in [doc/plugins/migration_helpers.md] on GitHub.
8
- #
9
- # [doc/plugins/migration_helpers.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/migration_helpers.md
10
- module MigrationHelpers
11
- def self.configure(uploader, delegate: false)
12
- uploader.opts[:migration_helpers_delegate] = delegate
13
- end
14
-
15
- module AttachmentMethods
16
- def initialize(name)
17
- super
18
-
19
- return if shrine_class.opts[:migration_helpers_delegate] == false
20
-
21
- name = attachment_name
22
-
23
- define_method :"update_#{name}" do |&block|
24
- send(:"#{name}_attacher").update_stored(&block)
25
- end
26
-
27
- define_method :"#{name}_cache" do
28
- send(:"#{name}_attacher").cache
29
- end
30
-
31
- define_method :"#{name}_store" do
32
- send(:"#{name}_attacher").store
33
- end
34
-
35
- define_method :"#{name}_cached?" do
36
- send(:"#{name}_attacher").cached?
37
- end
38
-
39
- define_method :"#{name}_stored?" do
40
- send(:"#{name}_attacher").stored?
41
- end
42
- end
43
- end
44
-
45
- module AttacherMethods
46
- # Updates the attachment with the result of the block. It will get
47
- # called only if the attachment exists and is stored.
48
- def update_stored(&block)
49
- return if get.nil? || cache.uploaded?(get)
50
- new_attachment = block.call(get)
51
- swap(new_attachment)
52
- end
53
-
54
- # Returns true if the attachment is present and is uploaded by the
55
- # temporary storage.
56
- def cached?
57
- get && cache.uploaded?(get)
58
- end
59
-
60
- # Returns true if the attachment is present and is uploaded by the
61
- # permanent storage.
62
- def stored?
63
- get && store.uploaded?(get)
64
- end
65
- end
66
- end
67
-
68
- register_plugin(:migration_helpers, MigrationHelpers)
69
- end
70
- end
@@ -1,57 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- Shrine.deprecation("The moving plugin has been deprecated in favor of the :move upload option for FileSystem storage. It will no longer be available in Shrine 3.")
4
-
5
- class Shrine
6
- module Plugins
7
- # Documentation lives in [doc/plugins/moving.md] on GitHub.
8
- #
9
- # [doc/plugins/moving.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/moving.md
10
- module Moving
11
- def self.configure(uploader, opts = {})
12
- uploader.opts[:moving_storages] = opts.fetch(:storages, uploader.opts[:moving_storages])
13
- end
14
-
15
- module InstanceMethods
16
- private
17
-
18
- # Moves the file if storage supports it, otherwise defaults to copying.
19
- def copy(io, context)
20
- if move?(io, context)
21
- move(io, context)
22
- else
23
- super
24
- end
25
- end
26
-
27
- # Generates upload options and calls `#move` on the storage.
28
- def move(io, context)
29
- location = context[:location]
30
- metadata = context[:metadata]
31
- upload_options = context[:upload_options] || {}
32
-
33
- storage.move(io, location, shrine_metadata: metadata, **upload_options)
34
- end
35
-
36
- # Returns true if file should be moved and is movable.
37
- def move?(io, context)
38
- return false if context[:move] == false
39
- moving_storage? && movable?(io, context)
40
- end
41
-
42
- # Returns true if storage can move this file.
43
- def movable?(io, context)
44
- storage.respond_to?(:move) && storage.movable?(io, context[:location])
45
- end
46
-
47
- # Returns true if file should be moved.
48
- def moving_storage?
49
- opts[:moving_storages].nil? ||
50
- opts[:moving_storages].include?(storage_key)
51
- end
52
- end
53
- end
54
-
55
- register_plugin(:moving, Moving)
56
- end
57
- end
@@ -1,32 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- Shrine.deprecation("The multi_delete plugin is deprecated and will be removed in Shrine 3.")
4
-
5
- class Shrine
6
- module Plugins
7
- # Documentation lives in [doc/plugins/multi_delete.md] on GitHub.
8
- #
9
- # [doc/plugins/multi_delete.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/multi_delete.md
10
- module MultiDelete
11
- module InstanceMethods
12
- private
13
-
14
- # Adds the ability to upload multiple files, leveraging the underlying
15
- # storage's potential multi delete capability.
16
- def _delete(uploaded_file, context)
17
- if uploaded_file.is_a?(Array)
18
- if storage.respond_to?(:multi_delete)
19
- storage.multi_delete(uploaded_file.map(&:id))
20
- else
21
- uploaded_file.each { |file| _delete(file, context) }
22
- end
23
- else
24
- super
25
- end
26
- end
27
- end
28
- end
29
-
30
- register_plugin(:multi_delete, MultiDelete)
31
- end
32
- end