shrine 3.1.0 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of shrine might be problematic. Click here for more details.

@@ -6,8 +6,8 @@ class Shrine
6
6
  module RefreshMetadata
7
7
  module AttacherMethods
8
8
  def refresh_metadata!(**options)
9
- file.refresh_metadata!(**context, **options)
10
- set(file)
9
+ file!.refresh_metadata!(**context, **options)
10
+ set(file) # trigger model write
11
11
  end
12
12
  end
13
13
 
@@ -9,18 +9,23 @@ class Shrine
9
9
  end
10
10
 
11
11
  module AttacherMethods
12
- def change(*)
12
+ def validate(*)
13
13
  super
14
14
  ensure
15
- revert_change if errors.any?
15
+ deassign if errors.any?
16
16
  end
17
17
 
18
18
  private
19
19
 
20
- def revert_change
20
+ def deassign
21
21
  destroy
22
- set @previous.file
23
- remove_instance_variable(:@previous)
22
+
23
+ if changed?
24
+ load_data @previous.data
25
+ @previous = nil
26
+ else
27
+ load_data nil
28
+ end
24
29
  end
25
30
  end
26
31
  end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Shrine
4
+ module Plugins
5
+ # Documentation can be found on https://shrinerb.com/docs/plugins/type_predicates
6
+ module TypePredicates
7
+ def self.configure(uploader, methods: [], **opts)
8
+ uploader.opts[:type_predicates] ||= { mime: :mini_mime }
9
+ uploader.opts[:type_predicates].merge!(opts)
10
+
11
+ methods.each do |name|
12
+ uploader::UploadedFile.send(:define_method, "#{name}?") { type?(name) }
13
+ end
14
+ end
15
+
16
+ module ClassMethods
17
+ def type_lookup(extension, database = nil)
18
+ database ||= opts[:type_predicates][:mime]
19
+ database = MimeDatabase.new(database) if database.is_a?(Symbol)
20
+ database.call(extension.to_s)
21
+ end
22
+ end
23
+
24
+ module FileMethods
25
+ def image?
26
+ general_type?("image")
27
+ end
28
+
29
+ def video?
30
+ general_type?("video")
31
+ end
32
+
33
+ def audio?
34
+ general_type?("audio")
35
+ end
36
+
37
+ def text?
38
+ general_type?("text")
39
+ end
40
+
41
+ def type?(type)
42
+ matching_mime_type = shrine_class.type_lookup(type)
43
+
44
+ fail Error, "type #{type.inspect} is not recognized by the MIME library" unless matching_mime_type
45
+
46
+ mime_type! == matching_mime_type
47
+ end
48
+
49
+ private
50
+
51
+ def general_type?(type)
52
+ mime_type!.start_with?(type)
53
+ end
54
+
55
+ def mime_type!
56
+ mime_type or fail Error, "mime_type metadata value is missing"
57
+ end
58
+ end
59
+
60
+ class MimeDatabase
61
+ SUPPORTED_TOOLS = %i[mini_mime mime_types mimemagic marcel rack_mime]
62
+
63
+ def initialize(tool)
64
+ raise Error, "unknown type database #{tool.inspect}, supported databases are: #{SUPPORTED_TOOLS.join(",")}" unless SUPPORTED_TOOLS.include?(tool)
65
+
66
+ @tool = tool
67
+ end
68
+
69
+ def call(extension)
70
+ send(:"lookup_with_#{@tool}", extension)
71
+ end
72
+
73
+ private
74
+
75
+ def lookup_with_mini_mime(extension)
76
+ require "mini_mime"
77
+
78
+ info = MiniMime.lookup_by_extension(extension)
79
+ info&.content_type
80
+ end
81
+
82
+ def lookup_with_mime_types(extension)
83
+ require "mime/types"
84
+
85
+ mime_type = MIME::Types.of(".#{extension}").first
86
+ mime_type&.content_type
87
+ end
88
+
89
+ def lookup_with_mimemagic(extension)
90
+ require "mimemagic"
91
+
92
+ magic = MimeMagic.by_extension(".#{extension}")
93
+ magic&.type
94
+ end
95
+
96
+ def lookup_with_marcel(extension)
97
+ require "marcel"
98
+
99
+ type = Marcel::MimeType.for(extension: ".#{extension}")
100
+ type unless type == "application/octet-stream"
101
+ end
102
+
103
+ def lookup_with_rack_mime(extension)
104
+ require "rack/mime"
105
+
106
+ Rack::Mime.mime_type(".#{extension}", nil)
107
+ end
108
+ end
109
+ end
110
+
111
+ register_plugin(:type_predicates, TypePredicates)
112
+ end
113
+ end
@@ -29,14 +29,16 @@ class Shrine
29
29
  @errors = []
30
30
  end
31
31
 
32
- # Leaves out :validate option when calling `Shrine.upload`.
33
- def upload(*args, validate: nil, **options)
34
- super(*args, **options)
32
+ # Performs validations after attaching cached file.
33
+ def attach_cached(value, validate: nil, **options)
34
+ result = super(value, validate: false, **options)
35
+ validation(validate)
36
+ result
35
37
  end
36
38
 
37
- # Performs validations after changing the file.
38
- def change(file, validate: nil, **)
39
- result = super
39
+ # Performs validations after attaching file.
40
+ def attach(io, validate: nil, **options)
41
+ result = super(io, **options)
40
42
  validation(validate)
41
43
  result
42
44
  end
@@ -179,25 +179,7 @@ class Shrine
179
179
  options.merge!(@upload_options)
180
180
  options.merge!(presign_options)
181
181
 
182
- if method == :post
183
- presigned_post = object(id).presigned_post(options)
184
-
185
- { method: method, url: presigned_post.url, fields: presigned_post.fields }
186
- else
187
- url = object(id).presigned_url(method, options)
188
-
189
- # When any of these options are specified, the corresponding request
190
- # headers must be included in the upload request.
191
- headers = {}
192
- headers["Content-Length"] = options[:content_length] if options[:content_length]
193
- headers["Content-Type"] = options[:content_type] if options[:content_type]
194
- headers["Content-Disposition"] = options[:content_disposition] if options[:content_disposition]
195
- headers["Content-Encoding"] = options[:content_encoding] if options[:content_encoding]
196
- headers["Content-Language"] = options[:content_language] if options[:content_language]
197
- headers["Content-MD5"] = options[:content_md5] if options[:content_md5]
198
-
199
- { method: method, url: url, headers: headers }
200
- end
182
+ send(:"presign_#{method}", id, options)
201
183
  end
202
184
 
203
185
  # Deletes the file from the storage.
@@ -235,6 +217,17 @@ class Shrine
235
217
 
236
218
  private
237
219
 
220
+ # Uploads the file to S3. Uses multipart upload for large files.
221
+ def put(io, id, **options)
222
+ if io.respond_to?(:size) && io.size && io.size <= @multipart_threshold[:upload]
223
+ object(id).put(body: io, **options)
224
+ else # multipart upload
225
+ object(id).upload_stream(part_size: part_size(io), **options) do |write_stream|
226
+ IO.copy_stream(io, write_stream)
227
+ end
228
+ end
229
+ end
230
+
238
231
  # Copies an existing S3 object to a new location. Uses multipart copy for
239
232
  # large files.
240
233
  def copy(io, id, **copy_options)
@@ -250,15 +243,28 @@ class Shrine
250
243
  object(id).copy_from(io.storage.object(io.id), **options)
251
244
  end
252
245
 
253
- # Uploads the file to S3. Uses multipart upload for large files.
254
- def put(io, id, **options)
255
- if io.respond_to?(:size) && io.size && io.size <= @multipart_threshold[:upload]
256
- object(id).put(body: io, **options)
257
- else # multipart upload
258
- object(id).upload_stream(part_size: part_size(io), **options) do |write_stream|
259
- IO.copy_stream(io, write_stream)
260
- end
261
- end
246
+ # Generates parameters for a POST upload request.
247
+ def presign_post(id, options)
248
+ presigned_post = object(id).presigned_post(options)
249
+
250
+ { method: :post, url: presigned_post.url, fields: presigned_post.fields }
251
+ end
252
+
253
+ # Generates parameters for a PUT upload request.
254
+ def presign_put(id, options)
255
+ url = object(id).presigned_url(:put, options)
256
+
257
+ # When any of these options are specified, the corresponding request
258
+ # headers must be included in the upload request.
259
+ headers = {}
260
+ headers["Content-Length"] = options[:content_length] if options[:content_length]
261
+ headers["Content-Type"] = options[:content_type] if options[:content_type]
262
+ headers["Content-Disposition"] = options[:content_disposition] if options[:content_disposition]
263
+ headers["Content-Encoding"] = options[:content_encoding] if options[:content_encoding]
264
+ headers["Content-Language"] = options[:content_language] if options[:content_language]
265
+ headers["Content-MD5"] = options[:content_md5] if options[:content_md5]
266
+
267
+ { method: :put, url: url, headers: headers }
262
268
  end
263
269
 
264
270
  # Determins the part size that should be used when uploading the given IO
@@ -7,7 +7,7 @@ class Shrine
7
7
 
8
8
  module VERSION
9
9
  MAJOR = 3
10
- MINOR = 1
10
+ MINOR = 2
11
11
  TINY = 0
12
12
  PRE = nil
13
13
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shrine
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.0
4
+ version: 3.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Janko Marohnić
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-11-15 00:00:00.000000000 Z
11
+ date: 2019-12-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: down
@@ -424,6 +424,7 @@ files:
424
424
  - doc/plugins/signature.md
425
425
  - doc/plugins/store_dimensions.md
426
426
  - doc/plugins/tempfile.md
427
+ - doc/plugins/type_predicates.md
427
428
  - doc/plugins/upload_endpoint.md
428
429
  - doc/plugins/upload_options.md
429
430
  - doc/plugins/url_options.md
@@ -468,9 +469,11 @@ files:
468
469
  - doc/release_notes/3.0.0.md
469
470
  - doc/release_notes/3.0.1.md
470
471
  - doc/release_notes/3.1.0.md
472
+ - doc/release_notes/3.2.0.md
471
473
  - doc/retrieving_uploads.md
472
474
  - doc/securing_uploads.md
473
475
  - doc/storage/file_system.md
476
+ - doc/storage/memory.md
474
477
  - doc/storage/s3.md
475
478
  - doc/testing.md
476
479
  - doc/upgrading_to_3.md
@@ -523,6 +526,7 @@ files:
523
526
  - lib/shrine/plugins/signature.rb
524
527
  - lib/shrine/plugins/store_dimensions.rb
525
528
  - lib/shrine/plugins/tempfile.rb
529
+ - lib/shrine/plugins/type_predicates.rb
526
530
  - lib/shrine/plugins/upload_endpoint.rb
527
531
  - lib/shrine/plugins/upload_options.rb
528
532
  - lib/shrine/plugins/url_options.rb
@@ -560,7 +564,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
560
564
  - !ruby/object:Gem::Version
561
565
  version: '0'
562
566
  requirements: []
563
- rubygems_version: 3.0.3
567
+ rubygems_version: 3.1.1
564
568
  signing_key:
565
569
  specification_version: 4
566
570
  summary: Toolkit for file attachments in Ruby applications