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
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
|