shrine 2.19.4 → 3.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +485 -43
- data/LICENSE.txt +1 -1
- data/README.md +81 -977
- 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 +102 -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 +1115 -0
- data/doc/metadata.md +190 -109
- data/doc/multiple_files.md +62 -34
- 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 +162 -101
- data/doc/plugins/derivatives.md +829 -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 +14 -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 +185 -167
- 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 +4 -0
- 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/retrieving_uploads.md +4 -1
- 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 +117 -83
- data/doc/testing.md +124 -144
- data/doc/upgrading_to_3.md +710 -0
- data/doc/validation.md +54 -90
- data/lib/shrine/attacher.rb +287 -171
- 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 +89 -134
- data/lib/shrine/plugins/derivatives.rb +637 -0
- data/lib/shrine/plugins/determine_mime_type.rb +9 -21
- data/lib/shrine/plugins/download_endpoint.rb +109 -133
- data/lib/shrine/plugins/dynamic_storage.rb +5 -11
- data/lib/shrine/plugins/entity.rb +152 -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 +13 -20
- data/lib/shrine/plugins/instrumentation.rb +54 -42
- 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 +158 -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 +18 -22
- 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 +15 -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 +10 -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 +25 -23
- 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 +34 -57
- 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 +154 -158
- data/lib/shrine/uploaded_file.rb +28 -30
- data/lib/shrine/version.rb +3 -3
- data/lib/shrine.rb +86 -149
- data/shrine.gemspec +9 -10
- metadata +79 -83
- 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
data/lib/shrine/plugins/copy.rb
DELETED
@@ -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
|
data/lib/shrine/plugins/hooks.rb
DELETED
@@ -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
|