shrine 2.19.3 → 3.6.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 +4 -4
- data/CHANGELOG.md +523 -41
- data/LICENSE.txt +1 -1
- data/README.md +83 -979
- data/doc/advantages.md +231 -204
- data/doc/attacher.md +304 -153
- data/doc/carrierwave.md +297 -226
- data/doc/changing_derivatives.md +308 -0
- data/doc/changing_location.md +103 -21
- data/doc/changing_storage.md +110 -0
- data/doc/creating_persistence_plugins.md +132 -0
- data/doc/creating_plugins.md +43 -23
- data/doc/creating_storages.md +19 -5
- data/doc/design.md +147 -97
- data/doc/direct_s3.md +38 -28
- data/doc/external/articles.md +63 -0
- data/doc/external/extensions.md +53 -0
- data/doc/external/misc.md +32 -0
- data/doc/getting_started.md +1156 -0
- data/doc/metadata.md +190 -109
- data/doc/multiple_files.md +93 -30
- data/doc/paperclip.md +384 -262
- data/doc/plugins/activerecord.md +177 -46
- data/doc/plugins/add_metadata.md +139 -38
- data/doc/plugins/atomic_helpers.md +217 -0
- data/doc/plugins/backgrounding.md +156 -98
- data/doc/plugins/cached_attachment_data.md +7 -5
- data/doc/plugins/column.md +121 -0
- data/doc/plugins/data_uri.md +23 -22
- data/doc/plugins/default_storage.md +36 -10
- data/doc/plugins/default_url.md +30 -13
- data/doc/plugins/delete_raw.md +4 -2
- data/doc/plugins/derivation_endpoint.md +186 -101
- data/doc/plugins/derivatives.md +839 -0
- data/doc/plugins/determine_mime_type.md +4 -2
- data/doc/plugins/download_endpoint.md +64 -8
- data/doc/plugins/dynamic_storage.md +5 -3
- data/doc/plugins/entity.md +263 -0
- data/doc/plugins/form_assign.md +55 -0
- data/doc/plugins/included.md +31 -8
- data/doc/plugins/infer_extension.md +21 -10
- data/doc/plugins/instrumentation.md +38 -16
- data/doc/plugins/keep_files.md +16 -17
- data/doc/plugins/metadata_attributes.md +42 -13
- data/doc/plugins/mirroring.md +118 -0
- data/doc/plugins/model.md +210 -0
- data/doc/plugins/module_include.md +4 -2
- data/doc/plugins/multi_cache.md +24 -0
- data/doc/plugins/persistence.md +101 -0
- data/doc/plugins/presign_endpoint.md +9 -4
- data/doc/plugins/pretty_location.md +16 -3
- data/doc/plugins/processing.md +4 -2
- data/doc/plugins/rack_file.md +8 -2
- data/doc/plugins/rack_response.md +6 -2
- data/doc/plugins/recache.md +4 -2
- data/doc/plugins/refresh_metadata.md +49 -9
- data/doc/plugins/remote_url.md +84 -47
- data/doc/plugins/remove_attachment.md +27 -6
- data/doc/plugins/remove_invalid.md +21 -6
- data/doc/plugins/restore_cached_data.md +11 -3
- data/doc/plugins/sequel.md +159 -35
- data/doc/plugins/signature.md +16 -5
- data/doc/plugins/store_dimensions.md +14 -2
- data/doc/plugins/tempfile.md +4 -2
- data/doc/plugins/type_predicates.md +96 -0
- data/doc/plugins/upload_endpoint.md +13 -13
- data/doc/plugins/upload_options.md +6 -4
- data/doc/plugins/{default_url_options.md → url_options.md} +9 -7
- data/doc/plugins/validation.md +97 -0
- data/doc/plugins/validation_helpers.md +16 -13
- data/doc/plugins/versions.md +15 -19
- data/doc/processing.md +438 -221
- data/doc/refile.md +188 -170
- data/doc/release_notes/1.0.0.md +4 -0
- data/doc/release_notes/1.1.0.md +6 -2
- data/doc/release_notes/1.2.0.md +4 -0
- data/doc/release_notes/1.3.0.md +4 -0
- data/doc/release_notes/1.4.0.md +4 -0
- data/doc/release_notes/1.4.1.md +4 -0
- data/doc/release_notes/1.4.2.md +4 -0
- data/doc/release_notes/2.0.0.md +4 -0
- data/doc/release_notes/2.0.1.md +4 -0
- data/doc/release_notes/2.1.0.md +5 -1
- data/doc/release_notes/2.1.1.md +4 -0
- data/doc/release_notes/2.10.0.md +4 -0
- data/doc/release_notes/2.10.1.md +4 -0
- data/doc/release_notes/2.11.0.md +4 -0
- data/doc/release_notes/2.12.0.md +4 -0
- data/doc/release_notes/2.13.0.md +4 -0
- data/doc/release_notes/2.14.0.md +5 -1
- data/doc/release_notes/2.15.0.md +11 -7
- data/doc/release_notes/2.16.0.md +4 -0
- data/doc/release_notes/2.17.0.md +4 -0
- data/doc/release_notes/2.18.0.md +4 -0
- data/doc/release_notes/2.19.0.md +6 -3
- data/doc/release_notes/2.2.0.md +4 -0
- data/doc/release_notes/2.3.0.md +4 -0
- data/doc/release_notes/2.3.1.md +4 -0
- data/doc/release_notes/2.4.0.md +4 -0
- data/doc/release_notes/2.4.1.md +4 -0
- data/doc/release_notes/2.5.0.md +4 -0
- data/doc/release_notes/2.6.0.md +4 -0
- data/doc/release_notes/2.6.1.md +4 -0
- data/doc/release_notes/2.7.0.md +4 -0
- data/doc/release_notes/2.8.0.md +4 -0
- data/doc/release_notes/2.9.0.md +4 -0
- data/doc/release_notes/3.0.0.md +981 -0
- data/doc/release_notes/3.0.1.md +22 -0
- data/doc/release_notes/3.1.0.md +73 -0
- data/doc/release_notes/3.2.0.md +96 -0
- data/doc/release_notes/3.2.1.md +31 -0
- data/doc/release_notes/3.2.2.md +14 -0
- data/doc/release_notes/3.3.0.md +105 -0
- data/doc/release_notes/3.4.0.md +35 -0
- data/doc/release_notes/3.5.0.md +63 -0
- data/doc/release_notes/3.6.0.md +23 -0
- data/doc/retrieving_uploads.md +5 -2
- data/doc/securing_uploads.md +60 -37
- data/doc/storage/file_system.md +20 -3
- data/doc/storage/memory.md +19 -0
- data/doc/storage/s3.md +122 -78
- data/doc/testing.md +141 -133
- data/doc/upgrading_to_3.md +708 -0
- data/doc/validation.md +54 -90
- data/lib/shrine/attacher.rb +292 -169
- data/lib/shrine/attachment.rb +13 -46
- data/lib/shrine/plugins/_persistence.rb +93 -0
- data/lib/shrine/plugins/activerecord.rb +77 -34
- data/lib/shrine/plugins/add_metadata.rb +25 -17
- data/lib/shrine/plugins/atomic_helpers.rb +119 -0
- data/lib/shrine/plugins/backgrounding.rb +77 -113
- data/lib/shrine/plugins/cached_attachment_data.rb +6 -15
- data/lib/shrine/plugins/column.rb +102 -0
- data/lib/shrine/plugins/data_uri.rb +38 -36
- data/lib/shrine/plugins/default_storage.rb +45 -15
- data/lib/shrine/plugins/default_url.rb +12 -24
- data/lib/shrine/plugins/default_url_options.rb +3 -30
- data/lib/shrine/plugins/delete_raw.rb +10 -16
- data/lib/shrine/plugins/derivation_endpoint.rb +130 -171
- data/lib/shrine/plugins/derivatives.rb +645 -0
- data/lib/shrine/plugins/determine_mime_type.rb +9 -21
- data/lib/shrine/plugins/download_endpoint.rb +118 -133
- data/lib/shrine/plugins/dynamic_storage.rb +5 -11
- data/lib/shrine/plugins/entity.rb +158 -0
- data/lib/shrine/plugins/form_assign.rb +108 -0
- data/lib/shrine/plugins/included.rb +6 -6
- data/lib/shrine/plugins/infer_extension.rb +17 -20
- data/lib/shrine/plugins/instrumentation.rb +59 -43
- data/lib/shrine/plugins/keep_files.rb +3 -15
- data/lib/shrine/plugins/metadata_attributes.rb +28 -19
- data/lib/shrine/plugins/mirroring.rb +142 -0
- data/lib/shrine/plugins/model.rb +160 -0
- data/lib/shrine/plugins/module_include.rb +3 -3
- data/lib/shrine/plugins/multi_cache.rb +27 -0
- data/lib/shrine/plugins/presign_endpoint.rb +27 -28
- data/lib/shrine/plugins/pretty_location.rb +15 -9
- data/lib/shrine/plugins/processing.rb +22 -9
- data/lib/shrine/plugins/rack_file.rb +2 -42
- data/lib/shrine/plugins/rack_response.rb +21 -10
- data/lib/shrine/plugins/recache.rb +6 -5
- data/lib/shrine/plugins/refresh_metadata.rb +13 -11
- data/lib/shrine/plugins/remote_url.rb +49 -49
- data/lib/shrine/plugins/remove_attachment.rb +12 -6
- data/lib/shrine/plugins/remove_invalid.rb +19 -8
- data/lib/shrine/plugins/restore_cached_data.rb +13 -7
- data/lib/shrine/plugins/sequel.rb +86 -36
- data/lib/shrine/plugins/signature.rb +10 -16
- data/lib/shrine/plugins/store_dimensions.rb +35 -40
- data/lib/shrine/plugins/tempfile.rb +1 -3
- data/lib/shrine/plugins/type_predicates.rb +113 -0
- data/lib/shrine/plugins/upload_endpoint.rb +28 -24
- data/lib/shrine/plugins/upload_options.rb +14 -15
- data/lib/shrine/plugins/url_options.rb +31 -0
- data/lib/shrine/plugins/validation.rb +80 -0
- data/lib/shrine/plugins/validation_helpers.rb +35 -58
- data/lib/shrine/plugins/versions.rb +107 -87
- data/lib/shrine/plugins.rb +22 -0
- data/lib/shrine/storage/file_system.rb +46 -64
- data/lib/shrine/storage/linter.rb +42 -7
- data/lib/shrine/storage/memory.rb +49 -0
- data/lib/shrine/storage/s3.rb +173 -160
- data/lib/shrine/uploaded_file.rb +32 -32
- data/lib/shrine/version.rb +3 -3
- data/lib/shrine.rb +87 -150
- data/shrine.gemspec +11 -12
- metadata +92 -82
- data/doc/migrating_storage.md +0 -76
- data/doc/plugins/backup.md +0 -31
- data/doc/plugins/copy.md +0 -24
- data/doc/plugins/delete_promoted.md +0 -12
- data/doc/plugins/direct_upload.md +0 -172
- data/doc/plugins/hooks.md +0 -58
- data/doc/plugins/logging.md +0 -42
- data/doc/plugins/migration_helpers.md +0 -60
- data/doc/plugins/moving.md +0 -19
- data/doc/plugins/multi_delete.md +0 -20
- data/doc/plugins/parallelize.md +0 -16
- data/doc/plugins/parsed_json.md +0 -23
- data/doc/regenerating_versions.md +0 -143
- data/lib/shrine/plugins/background_helpers.rb +0 -5
- data/lib/shrine/plugins/backup.rb +0 -90
- data/lib/shrine/plugins/copy.rb +0 -50
- data/lib/shrine/plugins/delete_promoted.rb +0 -20
- data/lib/shrine/plugins/direct_upload.rb +0 -217
- data/lib/shrine/plugins/hooks.rb +0 -90
- data/lib/shrine/plugins/logging.rb +0 -142
- data/lib/shrine/plugins/migration_helpers.rb +0 -70
- data/lib/shrine/plugins/moving.rb +0 -57
- data/lib/shrine/plugins/multi_delete.rb +0 -32
- data/lib/shrine/plugins/parallelize.rb +0 -78
- data/lib/shrine/plugins/parsed_json.rb +0 -29
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Shrine
|
|
4
|
+
module Plugins
|
|
5
|
+
# Documentation can be found on https://shrinerb.com/docs/plugins/model
|
|
6
|
+
module Model
|
|
7
|
+
def self.load_dependencies(uploader, **)
|
|
8
|
+
uploader.plugin :entity
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.configure(uploader, **opts)
|
|
12
|
+
uploader.opts[:model] ||= { cache: true }
|
|
13
|
+
uploader.opts[:model].merge!(opts)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
module AttachmentMethods
|
|
17
|
+
# Allows disabling model behaviour:
|
|
18
|
+
#
|
|
19
|
+
# Shrine::Attachment(:image) # model (default)
|
|
20
|
+
# Shrine::Attachment(:image, model: false) # entity
|
|
21
|
+
def initialize(name, model: true, **options)
|
|
22
|
+
super(name, **options)
|
|
23
|
+
@model = model
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# We define model methods only on inclusion. This gives other plugins
|
|
27
|
+
# the ability to disable model behaviour for entity classes. In this
|
|
28
|
+
# case we want to skip defining model methods as well.
|
|
29
|
+
def included(klass)
|
|
30
|
+
super
|
|
31
|
+
define_model_methods(@name) if model?
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
# Defines attachment setter and enhances the copy constructor.
|
|
37
|
+
def define_model_methods(name)
|
|
38
|
+
super if defined?(super)
|
|
39
|
+
|
|
40
|
+
define_method :"#{name}=" do |value|
|
|
41
|
+
send(:"#{name}_attacher").model_assign(value)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
define_method :"#{name}_changed?" do
|
|
45
|
+
send(:"#{name}_attacher").changed?
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# The copy constructor that's called on #dup and #clone.
|
|
49
|
+
define_method :initialize_copy do |other|
|
|
50
|
+
super(other)
|
|
51
|
+
attacher_copy = instance_variable_get(:"@#{name}_attacher")&.dup
|
|
52
|
+
attacher_copy.set_entity(self, name) if attacher_copy
|
|
53
|
+
instance_variable_set(:"@#{name}_attacher", attacher_copy)
|
|
54
|
+
self
|
|
55
|
+
end
|
|
56
|
+
private :initialize_copy
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Memoizes the attacher instance into an instance variable.
|
|
60
|
+
def attacher(record, **options)
|
|
61
|
+
return super unless model?
|
|
62
|
+
|
|
63
|
+
if !record.instance_variable_get(:"@#{@name}_attacher") || options.any?
|
|
64
|
+
attacher = class_attacher(**options)
|
|
65
|
+
attacher.load_model(record, @name)
|
|
66
|
+
|
|
67
|
+
record.instance_variable_set(:"@#{@name}_attacher", attacher)
|
|
68
|
+
else
|
|
69
|
+
record.instance_variable_get(:"@#{@name}_attacher")
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def model?
|
|
74
|
+
@model
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
module AttacherClassMethods
|
|
79
|
+
# Initializes itself from a model instance and attachment name.
|
|
80
|
+
#
|
|
81
|
+
# photo.image_data #=> "{...}" # a file is attached
|
|
82
|
+
#
|
|
83
|
+
# attacher = Attacher.from_model(photo, :image)
|
|
84
|
+
# attacher.file #=> #<Shrine::UploadedFile>
|
|
85
|
+
def from_model(record, name, **options)
|
|
86
|
+
attacher = new(**options)
|
|
87
|
+
attacher.load_model(record, name)
|
|
88
|
+
attacher
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
module AttacherMethods
|
|
93
|
+
def initialize(model_cache: shrine_class.opts[:model][:cache], **options)
|
|
94
|
+
super(**options)
|
|
95
|
+
@model_cache = model_cache
|
|
96
|
+
@model = nil
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Saves record and name and initializes attachment from the model
|
|
100
|
+
# attribute. Called from `Attacher.from_model`.
|
|
101
|
+
def load_model(record, name)
|
|
102
|
+
set_model(record, name)
|
|
103
|
+
read
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Saves record and name without loading attachment from the model
|
|
107
|
+
# attribute.
|
|
108
|
+
def set_model(record, name)
|
|
109
|
+
set_entity(record, name)
|
|
110
|
+
@model = true
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Called by the attachment attribute setter on the model.
|
|
114
|
+
def model_assign(value, **options)
|
|
115
|
+
if model_cache?
|
|
116
|
+
assign(value, **options)
|
|
117
|
+
else
|
|
118
|
+
attach(value, **options)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Writes uploaded file data into the model.
|
|
123
|
+
def set(*)
|
|
124
|
+
result = super
|
|
125
|
+
write if model?
|
|
126
|
+
result
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Writes the attachment data into the model attribute.
|
|
130
|
+
def write
|
|
131
|
+
column_values.each do |name, value|
|
|
132
|
+
write_attribute(name, value)
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
private
|
|
137
|
+
|
|
138
|
+
# Writes given value into the model attribute.
|
|
139
|
+
def write_attribute(name = attribute, value)
|
|
140
|
+
record.public_send(:"#{name}=", value)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Returns whether assigned files should be uploaded to/loaded from
|
|
144
|
+
# temporary storage.
|
|
145
|
+
def model_cache?
|
|
146
|
+
@model_cache
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Returns whether the attacher is being backed by a model instance.
|
|
150
|
+
# This allows users to still use the attacher with an entity instance
|
|
151
|
+
# or without any record instance.
|
|
152
|
+
def model?
|
|
153
|
+
@model
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
register_plugin(:model, Model)
|
|
159
|
+
end
|
|
160
|
+
end
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
Shrine.deprecation("The module_include plugin is deprecated and will be removed in Shrine 4. Override core classes directly instead.")
|
|
4
|
+
|
|
3
5
|
class Shrine
|
|
4
6
|
module Plugins
|
|
5
|
-
# Documentation
|
|
6
|
-
#
|
|
7
|
-
# [doc/plugins/module_include.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/module_include.md
|
|
7
|
+
# Documentation can be found on https://shrinerb.com/docs/plugins/module_include
|
|
8
8
|
module ModuleInclude
|
|
9
9
|
module ClassMethods
|
|
10
10
|
def attachment_module(mod = nil, &block)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Shrine
|
|
4
|
+
module Plugins
|
|
5
|
+
# Documentation can be found on https://shrinerb.com/docs/plugins/multi_cache
|
|
6
|
+
module MultiCache
|
|
7
|
+
def self.configure(uploader, **opts)
|
|
8
|
+
uploader.opts[:multi_cache] ||= {}
|
|
9
|
+
uploader.opts[:multi_cache].merge!(opts)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
module AttacherMethods
|
|
13
|
+
def cached?(file = self.file)
|
|
14
|
+
super || additional_cache.any? { |key| uploaded?(file, key) }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def additional_cache
|
|
20
|
+
Array(shrine_class.opts[:multi_cache][:additional_cache])
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
register_plugin(:multi_cache, MultiCache)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -6,11 +6,9 @@ require "json"
|
|
|
6
6
|
|
|
7
7
|
class Shrine
|
|
8
8
|
module Plugins
|
|
9
|
-
# Documentation
|
|
10
|
-
#
|
|
11
|
-
# [doc/plugins/presign_endpoint.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/presign_endpoint.md
|
|
9
|
+
# Documentation can be found on https://shrinerb.com/docs/plugins/presign_endpoint
|
|
12
10
|
module PresignEndpoint
|
|
13
|
-
def self.configure(uploader, opts
|
|
11
|
+
def self.configure(uploader, **opts)
|
|
14
12
|
uploader.opts[:presign_endpoint] ||= {}
|
|
15
13
|
uploader.opts[:presign_endpoint].merge!(opts)
|
|
16
14
|
end
|
|
@@ -83,12 +81,19 @@ class Shrine
|
|
|
83
81
|
|
|
84
82
|
status, headers, body = catch(:halt) do
|
|
85
83
|
error!(404, "Not Found") unless ["", "/"].include?(request.path_info)
|
|
86
|
-
error!(405, "Method Not Allowed") unless request.get?
|
|
87
84
|
|
|
88
|
-
|
|
85
|
+
if request.get?
|
|
86
|
+
handle_request(request)
|
|
87
|
+
elsif request.options?
|
|
88
|
+
handle_options_request(request)
|
|
89
|
+
else
|
|
90
|
+
error!(405, "Method Not Allowed")
|
|
91
|
+
end
|
|
89
92
|
end
|
|
90
93
|
|
|
91
|
-
headers[
|
|
94
|
+
headers = Rack::Headers[headers] if Rack.release >= "3"
|
|
95
|
+
headers["Content-Length"] ||= body.respond_to?(:bytesize) ? body.bytesize.to_s :
|
|
96
|
+
body.map(&:bytesize).inject(0, :+).to_s
|
|
92
97
|
|
|
93
98
|
[status, headers, body]
|
|
94
99
|
end
|
|
@@ -111,6 +116,13 @@ class Shrine
|
|
|
111
116
|
make_response(presign, request)
|
|
112
117
|
end
|
|
113
118
|
|
|
119
|
+
# Uppy client sends an OPTIONS request to fetch information about the
|
|
120
|
+
# Uppy Companion. Since our Rack app is only acting as Uppy Companion, we
|
|
121
|
+
# just return a successful response.
|
|
122
|
+
def handle_options_request(request)
|
|
123
|
+
[200, {}, []]
|
|
124
|
+
end
|
|
125
|
+
|
|
114
126
|
# Generates the location using `Shrine#generate_uid`, and extracts the
|
|
115
127
|
# extension from the `filename` query parameter. If `:presign_location`
|
|
116
128
|
# option is given, calls that instead.
|
|
@@ -137,20 +149,10 @@ class Shrine
|
|
|
137
149
|
if @presign
|
|
138
150
|
data = @presign.call(location, options, request)
|
|
139
151
|
else
|
|
140
|
-
data = storage.presign(location, options)
|
|
152
|
+
data = storage.presign(location, **options)
|
|
141
153
|
end
|
|
142
154
|
|
|
143
|
-
|
|
144
|
-
{ fields: {}, headers: {} }.merge(data.to_h)
|
|
145
|
-
else
|
|
146
|
-
Shrine.deprecation("Returning a custom object in Storage#presign is deprecated, presign_endpoint will not support it in Shrine 3. Storage#presign should return a Hash instead.")
|
|
147
|
-
|
|
148
|
-
url = data.url
|
|
149
|
-
fields = data.fields
|
|
150
|
-
headers = data.headers if data.respond_to?(:headers)
|
|
151
|
-
|
|
152
|
-
{ url: url, fields: fields.to_h, headers: headers.to_h }
|
|
153
|
-
end
|
|
155
|
+
{ fields: {}, headers: {} }.merge(data.to_h)
|
|
154
156
|
end
|
|
155
157
|
|
|
156
158
|
# Transforms the presign hash into a JSON response. It returns a Rack
|
|
@@ -158,16 +160,17 @@ class Shrine
|
|
|
158
160
|
# headers, and a body enumerable. If `:rack_response` option is given,
|
|
159
161
|
# calls that instead.
|
|
160
162
|
def make_response(object, request)
|
|
161
|
-
if @rack_response
|
|
162
|
-
|
|
163
|
+
status, headers, body = if @rack_response
|
|
164
|
+
@rack_response.call(object, request)
|
|
163
165
|
else
|
|
164
|
-
|
|
166
|
+
[200, { "Content-Type" => CONTENT_TYPE_JSON }, [object.to_json]]
|
|
165
167
|
end
|
|
166
168
|
|
|
169
|
+
headers = Rack::Headers[headers] if Rack.release >= "3"
|
|
167
170
|
# prevent browsers from caching the response
|
|
168
|
-
|
|
171
|
+
headers["Cache-Control"] = "no-store" unless headers.key?("Cache-Control")
|
|
169
172
|
|
|
170
|
-
|
|
173
|
+
[status, headers, body]
|
|
171
174
|
end
|
|
172
175
|
|
|
173
176
|
# Used for early returning an error response.
|
|
@@ -185,8 +188,4 @@ class Shrine
|
|
|
185
188
|
@shrine_class.find_storage(@storage_key)
|
|
186
189
|
end
|
|
187
190
|
end
|
|
188
|
-
|
|
189
|
-
# backwards compatibility
|
|
190
|
-
Plugins::PresignEndpoint.const_set(:App, PresignEndpoint)
|
|
191
|
-
Plugins::PresignEndpoint.deprecate_constant(:App)
|
|
192
191
|
end
|
|
@@ -2,28 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
class Shrine
|
|
4
4
|
module Plugins
|
|
5
|
-
# Documentation
|
|
6
|
-
#
|
|
7
|
-
# [doc/plugins/pretty_location.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/pretty_location.md
|
|
5
|
+
# Documentation can be found on https://shrinerb.com/docs/plugins/pretty_location
|
|
8
6
|
module PrettyLocation
|
|
9
|
-
def self.configure(uploader, opts
|
|
7
|
+
def self.configure(uploader, **opts)
|
|
10
8
|
uploader.opts[:pretty_location] ||= { identifier: :id }
|
|
11
9
|
uploader.opts[:pretty_location].merge!(opts)
|
|
12
10
|
end
|
|
13
11
|
|
|
14
12
|
module InstanceMethods
|
|
15
|
-
def generate_location(io,
|
|
16
|
-
pretty_location(io,
|
|
13
|
+
def generate_location(io, **options)
|
|
14
|
+
pretty_location(io, **options)
|
|
17
15
|
end
|
|
18
16
|
|
|
19
|
-
def pretty_location(io, name: nil, record: nil, version: nil, identifier: nil, metadata: {}, **)
|
|
17
|
+
def pretty_location(io, name: nil, record: nil, version: nil, derivative: nil, identifier: nil, metadata: {}, **)
|
|
20
18
|
if record
|
|
21
19
|
namespace = record_namespace(record)
|
|
22
20
|
identifier ||= record_identifier(record)
|
|
23
21
|
end
|
|
24
22
|
|
|
25
23
|
basename = basic_location(io, metadata: metadata)
|
|
26
|
-
basename =
|
|
24
|
+
basename = [*(version || derivative), basename].join("-")
|
|
27
25
|
|
|
28
26
|
[*namespace, *identifier, *name, basename].join("/")
|
|
29
27
|
end
|
|
@@ -34,9 +32,17 @@ class Shrine
|
|
|
34
32
|
record.public_send(opts[:pretty_location][:identifier])
|
|
35
33
|
end
|
|
36
34
|
|
|
35
|
+
def transform_class_name(class_name)
|
|
36
|
+
if opts[:pretty_location][:class_underscore]
|
|
37
|
+
class_name.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').gsub(/([a-z])([A-Z])/, '\1_\2').downcase
|
|
38
|
+
else
|
|
39
|
+
class_name.downcase
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
37
43
|
def record_namespace(record)
|
|
38
44
|
class_name = record.class.name or return
|
|
39
|
-
parts = class_name.
|
|
45
|
+
parts = transform_class_name(class_name).split("::")
|
|
40
46
|
|
|
41
47
|
if separator = opts[:pretty_location][:namespace]
|
|
42
48
|
parts.join(separator)
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
Shrine.deprecation("The processing plugin is deprecated and will be removed in Shrine 4. If you were using it with versions plugin, use the new derivatives plugin instead.")
|
|
4
|
+
|
|
3
5
|
class Shrine
|
|
4
6
|
module Plugins
|
|
5
|
-
# Documentation
|
|
6
|
-
#
|
|
7
|
-
# [doc/plugins/processing.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/processing.md
|
|
7
|
+
# Documentation can be found on https://shrinerb.com/docs/plugins/processing
|
|
8
8
|
module Processing
|
|
9
9
|
def self.configure(uploader)
|
|
10
10
|
uploader.opts[:processing] ||= {}
|
|
@@ -13,19 +13,32 @@ class Shrine
|
|
|
13
13
|
module ClassMethods
|
|
14
14
|
def process(action, &block)
|
|
15
15
|
opts[:processing][action] ||= []
|
|
16
|
-
opts[:processing][action]
|
|
16
|
+
opts[:processing][action] << block
|
|
17
17
|
end
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
module InstanceMethods
|
|
21
|
-
def
|
|
22
|
-
|
|
21
|
+
def upload(io, process: true, **options)
|
|
22
|
+
if process
|
|
23
|
+
input = process(io, **options)
|
|
24
|
+
else
|
|
25
|
+
input = io
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
super(input, **options)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
23
32
|
|
|
24
|
-
|
|
25
|
-
|
|
33
|
+
def process(io, **options)
|
|
34
|
+
pipeline = processing_pipeline(options[:action])
|
|
35
|
+
pipeline.inject(io) do |input, processor|
|
|
36
|
+
instance_exec(input, **options, &processor) || input
|
|
26
37
|
end
|
|
38
|
+
end
|
|
27
39
|
|
|
28
|
-
|
|
40
|
+
def processing_pipeline(key)
|
|
41
|
+
opts[:processing][key] || []
|
|
29
42
|
end
|
|
30
43
|
end
|
|
31
44
|
end
|
|
@@ -4,9 +4,7 @@ require "forwardable"
|
|
|
4
4
|
|
|
5
5
|
class Shrine
|
|
6
6
|
module Plugins
|
|
7
|
-
# Documentation
|
|
8
|
-
#
|
|
9
|
-
# [doc/plugins/rack_file.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/rack_file.md
|
|
7
|
+
# Documentation can be found on https://shrinerb.com/docs/plugins/rack_file
|
|
10
8
|
module RackFile
|
|
11
9
|
module ClassMethods
|
|
12
10
|
# Accepts a Rack uploaded file hash and wraps it in an IO object.
|
|
@@ -23,46 +21,12 @@ class Shrine
|
|
|
23
21
|
end
|
|
24
22
|
end
|
|
25
23
|
|
|
26
|
-
module InstanceMethods
|
|
27
|
-
# If `io` is a Rack uploaded file hash, converts it to an IO-like
|
|
28
|
-
# object and calls `super`.
|
|
29
|
-
def upload(io, context = {})
|
|
30
|
-
super(convert_rack_file(io), context)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# If `io` is a Rack uploaded file hash, converts it to an IO-like
|
|
34
|
-
# object and calls `super`.
|
|
35
|
-
def store(io, context = {})
|
|
36
|
-
super(convert_rack_file(io), context)
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
private
|
|
40
|
-
|
|
41
|
-
# If given a Rack uploaded file hash, returns a
|
|
42
|
-
# `Shrine::Plugins::RackFile::UploadedFile` IO-like object wrapping that
|
|
43
|
-
# hash, otherwise returns the value unchanged.
|
|
44
|
-
def convert_rack_file(value)
|
|
45
|
-
if rack_file?(value)
|
|
46
|
-
Shrine.deprecation("Passing a Rack uploaded file hash to Shrine#upload is deprecated, use Shrine.rack_file to convert the Rack file hash into an IO object.")
|
|
47
|
-
self.class.rack_file(value)
|
|
48
|
-
else
|
|
49
|
-
value
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
# Returns whether a given value is a Rack uploaded file hash, by
|
|
54
|
-
# checking whether it's a hash with `:tempfile` and `:name` keys.
|
|
55
|
-
def rack_file?(value)
|
|
56
|
-
value.is_a?(Hash) && value.key?(:tempfile) && value.key?(:name)
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
|
|
60
24
|
module AttacherMethods
|
|
61
25
|
# Checks whether a file is a Rack file hash, and in that case wraps the
|
|
62
26
|
# hash in an IO-like object.
|
|
63
27
|
def assign(value, **options)
|
|
64
28
|
if rack_file?(value)
|
|
65
|
-
assign
|
|
29
|
+
assign shrine_class.rack_file(value), **options
|
|
66
30
|
else
|
|
67
31
|
super
|
|
68
32
|
end
|
|
@@ -101,8 +65,4 @@ class Shrine
|
|
|
101
65
|
extend Forwardable
|
|
102
66
|
delegate [:read, :size, :rewind, :eof?, :close] => :@tempfile
|
|
103
67
|
end
|
|
104
|
-
|
|
105
|
-
# backwards compatibility
|
|
106
|
-
Plugins::RackFile.const_set(:UploadedFile, RackFile)
|
|
107
|
-
Plugins::RackFile.deprecate_constant(:UploadedFile)
|
|
108
68
|
end
|
|
@@ -6,9 +6,7 @@ require "digest"
|
|
|
6
6
|
|
|
7
7
|
class Shrine
|
|
8
8
|
module Plugins
|
|
9
|
-
# Documentation
|
|
10
|
-
#
|
|
11
|
-
# [doc/plugins/rack_response.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/rack_response.md
|
|
9
|
+
# Documentation can be found on https://shrinerb.com/docs/plugins/rack_response
|
|
12
10
|
module RackResponse
|
|
13
11
|
module FileMethods
|
|
14
12
|
# Returns a Rack response triple for the uploaded file.
|
|
@@ -34,6 +32,8 @@ class Shrine
|
|
|
34
32
|
headers = rack_headers(**options)
|
|
35
33
|
body = rack_body(**options)
|
|
36
34
|
|
|
35
|
+
headers = Rack::Headers[headers] if Rack.release >= "3"
|
|
36
|
+
|
|
37
37
|
[status, headers, body]
|
|
38
38
|
end
|
|
39
39
|
|
|
@@ -101,16 +101,23 @@ class Shrine
|
|
|
101
101
|
FileBody.new(file, range: range)
|
|
102
102
|
end
|
|
103
103
|
|
|
104
|
-
#
|
|
104
|
+
# Retrieves a range value parsed from HTTP "Range" header.
|
|
105
105
|
def parse_content_range(range_header)
|
|
106
|
-
|
|
107
|
-
ranges = Rack::Utils.get_byte_ranges(range_header, file.size)
|
|
108
|
-
else
|
|
109
|
-
ranges = Rack::Utils.byte_ranges({ "HTTP_RANGE" => range_header }, file.size)
|
|
110
|
-
end
|
|
111
|
-
|
|
106
|
+
ranges = get_byte_ranges(range_header)
|
|
112
107
|
ranges.first if ranges && ranges.one?
|
|
113
108
|
end
|
|
109
|
+
|
|
110
|
+
if Rack.release >= "2.0"
|
|
111
|
+
def get_byte_ranges(range_header)
|
|
112
|
+
Rack::Utils.get_byte_ranges(range_header, file.size)
|
|
113
|
+
end
|
|
114
|
+
else
|
|
115
|
+
# :nocov:
|
|
116
|
+
def get_byte_ranges(range_header)
|
|
117
|
+
Rack::Utils.byte_ranges({ "HTTP_RANGE" => range_header }, file.size)
|
|
118
|
+
end
|
|
119
|
+
# :nocov:
|
|
120
|
+
end
|
|
114
121
|
end
|
|
115
122
|
|
|
116
123
|
# Implements the interface of a Rack response body object.
|
|
@@ -136,6 +143,10 @@ class Shrine
|
|
|
136
143
|
file.close
|
|
137
144
|
end
|
|
138
145
|
|
|
146
|
+
def bytesize
|
|
147
|
+
each.inject(0) { |sum, chunk| sum += chunk.length }
|
|
148
|
+
end
|
|
149
|
+
|
|
139
150
|
# Rack::Sendfile is activated when response body responds to #to_path.
|
|
140
151
|
def respond_to_missing?(name, include_private = false)
|
|
141
152
|
name == :to_path && path
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
Shrine.deprecation("The recache plugin is deprecated and will be removed in Shrine 4. If you were using it with versions plugin, use the new derivatives plugin instead.")
|
|
4
|
+
|
|
3
5
|
class Shrine
|
|
4
6
|
module Plugins
|
|
5
|
-
# Documentation
|
|
6
|
-
#
|
|
7
|
-
# [doc/plugins/recache.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/recache.md
|
|
7
|
+
# Documentation can be found on https://shrinerb.com/docs/plugins/recache
|
|
8
8
|
module Recache
|
|
9
9
|
module AttacherMethods
|
|
10
10
|
def save
|
|
@@ -14,8 +14,9 @@ class Shrine
|
|
|
14
14
|
|
|
15
15
|
def recache
|
|
16
16
|
if cached?
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
result = upload(file, cache_key, action: :recache)
|
|
18
|
+
|
|
19
|
+
set(result)
|
|
19
20
|
end
|
|
20
21
|
end
|
|
21
22
|
end
|
|
@@ -2,20 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
class Shrine
|
|
4
4
|
module Plugins
|
|
5
|
-
# Documentation
|
|
6
|
-
#
|
|
7
|
-
# [doc/plugins/refresh_metadata.md]: https://github.com/shrinerb/shrine/blob/master/doc/plugins/refresh_metadata.md
|
|
5
|
+
# Documentation can be found on https://shrinerb.com/docs/plugins/refresh_metadata
|
|
8
6
|
module RefreshMetadata
|
|
7
|
+
module AttacherMethods
|
|
8
|
+
def refresh_metadata!(**options)
|
|
9
|
+
file!.refresh_metadata!(**context, **options)
|
|
10
|
+
set(file) # trigger model write
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
9
14
|
module FileMethods
|
|
10
|
-
def refresh_metadata!(**
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
else
|
|
15
|
-
open { uploader.send(:get_metadata, self, metadata: true, **context) }
|
|
16
|
-
end
|
|
15
|
+
def refresh_metadata!(**options)
|
|
16
|
+
return open { refresh_metadata!(**options) } unless opened?
|
|
17
|
+
|
|
18
|
+
refreshed_metadata = uploader.send(:get_metadata, self, metadata: true, **options)
|
|
17
19
|
|
|
18
|
-
@
|
|
20
|
+
@metadata = @metadata.merge(refreshed_metadata)
|
|
19
21
|
end
|
|
20
22
|
end
|
|
21
23
|
end
|