activestorage 6.1.7 → 7.1.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 +152 -276
- data/MIT-LICENSE +1 -1
- data/README.md +29 -15
- data/app/assets/javascripts/activestorage.esm.js +848 -0
- data/app/assets/javascripts/activestorage.js +263 -376
- data/app/controllers/active_storage/base_controller.rb +0 -9
- data/app/controllers/active_storage/blobs/proxy_controller.rb +16 -4
- data/app/controllers/active_storage/blobs/redirect_controller.rb +6 -4
- data/app/controllers/active_storage/disk_controller.rb +5 -2
- data/app/controllers/active_storage/representations/base_controller.rb +5 -1
- data/app/controllers/active_storage/representations/proxy_controller.rb +8 -3
- data/app/controllers/active_storage/representations/redirect_controller.rb +6 -4
- data/app/controllers/concerns/active_storage/disable_session.rb +12 -0
- data/app/controllers/concerns/active_storage/file_server.rb +4 -1
- data/app/controllers/concerns/active_storage/set_blob.rb +6 -2
- data/app/controllers/concerns/active_storage/set_current.rb +3 -3
- data/app/controllers/concerns/active_storage/streaming.rb +66 -0
- data/app/javascript/activestorage/blob_record.js +4 -1
- data/app/javascript/activestorage/direct_upload.js +3 -2
- data/app/javascript/activestorage/index.js +3 -1
- data/app/javascript/activestorage/ujs.js +1 -1
- data/app/jobs/active_storage/analyze_job.rb +1 -1
- data/app/jobs/active_storage/mirror_job.rb +1 -1
- data/app/jobs/active_storage/purge_job.rb +1 -1
- data/app/jobs/active_storage/transform_job.rb +12 -0
- data/app/models/active_storage/attachment.rb +111 -4
- data/app/models/active_storage/blob/analyzable.rb +4 -3
- data/app/models/active_storage/blob/identifiable.rb +1 -0
- data/app/models/active_storage/blob/representable.rb +14 -8
- data/app/models/active_storage/blob.rb +93 -57
- data/app/models/active_storage/current.rb +2 -2
- data/app/models/active_storage/filename.rb +2 -0
- data/app/models/active_storage/named_variant.rb +21 -0
- data/app/models/active_storage/preview.rb +11 -7
- data/app/models/active_storage/record.rb +1 -1
- data/app/models/active_storage/variant.rb +10 -12
- data/app/models/active_storage/variant_record.rb +2 -0
- data/app/models/active_storage/variant_with_record.rb +28 -12
- data/app/models/active_storage/variation.rb +7 -5
- data/config/routes.rb +12 -10
- data/db/migrate/20170806125915_create_active_storage_tables.rb +15 -6
- data/db/update_migrate/20211119233751_remove_not_null_on_active_storage_blobs_checksum.rb +7 -0
- data/lib/active_storage/analyzer/audio_analyzer.rb +77 -0
- data/lib/active_storage/analyzer/image_analyzer/image_magick.rb +41 -0
- data/lib/active_storage/analyzer/image_analyzer/vips.rb +51 -0
- data/lib/active_storage/analyzer/image_analyzer.rb +4 -30
- data/lib/active_storage/analyzer/video_analyzer.rb +41 -17
- data/lib/active_storage/analyzer.rb +10 -4
- data/lib/active_storage/attached/changes/create_many.rb +14 -5
- data/lib/active_storage/attached/changes/create_one.rb +46 -4
- data/lib/active_storage/attached/changes/create_one_of_many.rb +1 -1
- data/lib/active_storage/attached/changes/delete_many.rb +1 -1
- data/lib/active_storage/attached/changes/delete_one.rb +1 -1
- data/lib/active_storage/attached/changes/detach_many.rb +18 -0
- data/lib/active_storage/attached/changes/detach_one.rb +24 -0
- data/lib/active_storage/attached/changes/purge_many.rb +27 -0
- data/lib/active_storage/attached/changes/purge_one.rb +27 -0
- data/lib/active_storage/attached/changes.rb +7 -1
- data/lib/active_storage/attached/many.rb +32 -19
- data/lib/active_storage/attached/model.rb +80 -29
- data/lib/active_storage/attached/one.rb +37 -31
- data/lib/active_storage/attached.rb +2 -0
- data/lib/active_storage/deprecator.rb +7 -0
- data/lib/active_storage/downloader.rb +4 -4
- data/lib/active_storage/engine.rb +55 -7
- data/lib/active_storage/fixture_set.rb +75 -0
- data/lib/active_storage/gem_version.rb +3 -3
- data/lib/active_storage/log_subscriber.rb +12 -0
- data/lib/active_storage/previewer.rb +12 -5
- data/lib/active_storage/reflection.rb +12 -2
- data/lib/active_storage/service/azure_storage_service.rb +30 -6
- data/lib/active_storage/service/configurator.rb +1 -1
- data/lib/active_storage/service/disk_service.rb +26 -19
- data/lib/active_storage/service/gcs_service.rb +100 -11
- data/lib/active_storage/service/mirror_service.rb +12 -7
- data/lib/active_storage/service/registry.rb +1 -1
- data/lib/active_storage/service/s3_service.rb +39 -15
- data/lib/active_storage/service.rb +17 -7
- data/lib/active_storage/transformers/image_processing_transformer.rb +1 -1
- data/lib/active_storage/transformers/transformer.rb +3 -1
- data/lib/active_storage/version.rb +1 -1
- data/lib/active_storage.rb +22 -2
- metadata +30 -30
- data/app/controllers/concerns/active_storage/set_headers.rb +0 -12
@@ -12,7 +12,10 @@ require "active_storage/previewer/mupdf_previewer"
|
|
12
12
|
require "active_storage/previewer/video_previewer"
|
13
13
|
|
14
14
|
require "active_storage/analyzer/image_analyzer"
|
15
|
+
require "active_storage/analyzer/image_analyzer/image_magick"
|
16
|
+
require "active_storage/analyzer/image_analyzer/vips"
|
15
17
|
require "active_storage/analyzer/video_analyzer"
|
18
|
+
require "active_storage/analyzer/audio_analyzer"
|
16
19
|
|
17
20
|
require "active_storage/service/registry"
|
18
21
|
|
@@ -24,33 +27,33 @@ module ActiveStorage
|
|
24
27
|
|
25
28
|
config.active_storage = ActiveSupport::OrderedOptions.new
|
26
29
|
config.active_storage.previewers = [ ActiveStorage::Previewer::PopplerPDFPreviewer, ActiveStorage::Previewer::MuPDFPreviewer, ActiveStorage::Previewer::VideoPreviewer ]
|
27
|
-
config.active_storage.analyzers = [ ActiveStorage::Analyzer::ImageAnalyzer, ActiveStorage::Analyzer::VideoAnalyzer ]
|
30
|
+
config.active_storage.analyzers = [ ActiveStorage::Analyzer::ImageAnalyzer::Vips, ActiveStorage::Analyzer::ImageAnalyzer::ImageMagick, ActiveStorage::Analyzer::VideoAnalyzer, ActiveStorage::Analyzer::AudioAnalyzer ]
|
28
31
|
config.active_storage.paths = ActiveSupport::OrderedOptions.new
|
29
32
|
config.active_storage.queues = ActiveSupport::InheritableOptions.new
|
33
|
+
config.active_storage.precompile_assets = true
|
30
34
|
|
31
35
|
config.active_storage.variable_content_types = %w(
|
32
36
|
image/png
|
33
37
|
image/gif
|
34
|
-
image/jpg
|
35
38
|
image/jpeg
|
36
|
-
image/pjpeg
|
37
39
|
image/tiff
|
38
40
|
image/bmp
|
39
41
|
image/vnd.adobe.photoshop
|
40
42
|
image/vnd.microsoft.icon
|
41
43
|
image/webp
|
44
|
+
image/avif
|
45
|
+
image/heic
|
46
|
+
image/heif
|
42
47
|
)
|
43
48
|
|
44
49
|
config.active_storage.web_image_content_types = %w(
|
45
50
|
image/png
|
46
51
|
image/jpeg
|
47
|
-
image/jpg
|
48
52
|
image/gif
|
49
53
|
)
|
50
54
|
|
51
55
|
config.active_storage.content_types_to_serve_as_binary = %w(
|
52
56
|
text/html
|
53
|
-
text/javascript
|
54
57
|
image/svg+xml
|
55
58
|
application/postscript
|
56
59
|
application/x-shockwave-flash
|
@@ -64,7 +67,6 @@ module ActiveStorage
|
|
64
67
|
config.active_storage.content_types_allowed_inline = %w(
|
65
68
|
image/png
|
66
69
|
image/gif
|
67
|
-
image/jpg
|
68
70
|
image/jpeg
|
69
71
|
image/tiff
|
70
72
|
image/bmp
|
@@ -75,6 +77,10 @@ module ActiveStorage
|
|
75
77
|
|
76
78
|
config.eager_load_namespaces << ActiveStorage
|
77
79
|
|
80
|
+
initializer "active_storage.deprecator", before: :load_environment_config do |app|
|
81
|
+
app.deprecators[:active_storage] = ActiveStorage.deprecator
|
82
|
+
end
|
83
|
+
|
78
84
|
initializer "active_storage.configs" do
|
79
85
|
config.after_initialize do |app|
|
80
86
|
ActiveStorage.logger = app.config.active_storage.logger || Rails.logger
|
@@ -105,11 +111,19 @@ module ActiveStorage
|
|
105
111
|
ActiveStorage.web_image_content_types = app.config.active_storage.web_image_content_types || []
|
106
112
|
ActiveStorage.content_types_to_serve_as_binary = app.config.active_storage.content_types_to_serve_as_binary || []
|
107
113
|
ActiveStorage.service_urls_expire_in = app.config.active_storage.service_urls_expire_in || 5.minutes
|
114
|
+
ActiveStorage.urls_expire_in = app.config.active_storage.urls_expire_in
|
108
115
|
ActiveStorage.content_types_allowed_inline = app.config.active_storage.content_types_allowed_inline || []
|
109
116
|
ActiveStorage.binary_content_type = app.config.active_storage.binary_content_type || "application/octet-stream"
|
110
117
|
ActiveStorage.video_preview_arguments = app.config.active_storage.video_preview_arguments || "-y -vframes 1 -f image2"
|
111
118
|
|
112
|
-
|
119
|
+
unless app.config.active_storage.silence_invalid_content_types_warning.nil?
|
120
|
+
ActiveStorage.silence_invalid_content_types_warning = app.config.active_storage.silence_invalid_content_types_warning
|
121
|
+
end
|
122
|
+
|
123
|
+
unless app.config.active_storage.replace_on_assign_to_many.nil?
|
124
|
+
ActiveStorage.replace_on_assign_to_many = app.config.active_storage.replace_on_assign_to_many
|
125
|
+
end
|
126
|
+
|
113
127
|
ActiveStorage.track_variants = app.config.active_storage.track_variants || false
|
114
128
|
end
|
115
129
|
end
|
@@ -159,5 +173,39 @@ module ActiveStorage
|
|
159
173
|
ActiveRecord::Reflection.singleton_class.prepend(Reflection::ReflectionExtension)
|
160
174
|
end
|
161
175
|
end
|
176
|
+
|
177
|
+
initializer "action_view.configuration" do
|
178
|
+
config.after_initialize do |app|
|
179
|
+
ActiveSupport.on_load(:action_view) do
|
180
|
+
multiple_file_field_include_hidden = app.config.active_storage.delete(:multiple_file_field_include_hidden)
|
181
|
+
|
182
|
+
unless multiple_file_field_include_hidden.nil?
|
183
|
+
ActionView::Helpers::FormHelper.multiple_file_field_include_hidden = multiple_file_field_include_hidden
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
initializer "active_storage.asset" do
|
190
|
+
config.after_initialize do |app|
|
191
|
+
if app.config.respond_to?(:assets) && app.config.active_storage.precompile_assets
|
192
|
+
app.config.assets.precompile += %w( activestorage activestorage.esm )
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
initializer "active_storage.fixture_set" do
|
198
|
+
ActiveSupport.on_load(:active_record_fixture_set) do
|
199
|
+
ActiveStorage::FixtureSet.file_fixture_path ||= Rails.root.join(*[
|
200
|
+
ENV.fetch("FIXTURES_PATH") { File.join("test", "fixtures") },
|
201
|
+
ENV["FIXTURES_DIR"],
|
202
|
+
"files"
|
203
|
+
].compact_blank)
|
204
|
+
end
|
205
|
+
|
206
|
+
ActiveSupport.on_load(:active_support_test_case) do
|
207
|
+
ActiveStorage::FixtureSet.file_fixture_path = ActiveSupport::TestCase.file_fixture_path
|
208
|
+
end
|
209
|
+
end
|
162
210
|
end
|
163
211
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/testing/file_fixtures"
|
4
|
+
require "active_record/secure_token"
|
5
|
+
|
6
|
+
module ActiveStorage
|
7
|
+
# = Active Storage \FixtureSet
|
8
|
+
#
|
9
|
+
# Fixtures are a way of organizing data that you want to test against; in
|
10
|
+
# short, sample data.
|
11
|
+
#
|
12
|
+
# To learn more about fixtures, read the ActiveRecord::FixtureSet documentation.
|
13
|
+
#
|
14
|
+
# === YAML
|
15
|
+
#
|
16
|
+
# Like other Active Record-backed models, ActiveStorage::Attachment and
|
17
|
+
# ActiveStorage::Blob records inherit from ActiveRecord::Base instances and
|
18
|
+
# therefore can be populated by fixtures.
|
19
|
+
#
|
20
|
+
# Consider a hypothetical <tt>Article</tt> model class, its related
|
21
|
+
# fixture data, as well as fixture data for related ActiveStorage::Attachment
|
22
|
+
# and ActiveStorage::Blob records:
|
23
|
+
#
|
24
|
+
# # app/models/article.rb
|
25
|
+
# class Article < ApplicationRecord
|
26
|
+
# has_one_attached :thumbnail
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# # fixtures/active_storage/blobs.yml
|
30
|
+
# first_thumbnail_blob: <%= ActiveStorage::FixtureSet.blob filename: "first.png" %>
|
31
|
+
#
|
32
|
+
# # fixtures/active_storage/attachments.yml
|
33
|
+
# first_thumbnail_attachment:
|
34
|
+
# name: thumbnail
|
35
|
+
# record: first (Article)
|
36
|
+
# blob: first_thumbnail_blob
|
37
|
+
#
|
38
|
+
# When processed, Active Record will insert database records for each fixture
|
39
|
+
# entry and will ensure the Active Storage relationship is intact.
|
40
|
+
class FixtureSet
|
41
|
+
include ActiveSupport::Testing::FileFixtures
|
42
|
+
include ActiveRecord::SecureToken
|
43
|
+
|
44
|
+
# Generate a YAML-encoded representation of an ActiveStorage::Blob
|
45
|
+
# instance's attributes, resolve the file relative to the directory mentioned
|
46
|
+
# by ActiveSupport::Testing::FileFixtures.file_fixture, and upload
|
47
|
+
# the file to the Service
|
48
|
+
#
|
49
|
+
# === Examples
|
50
|
+
#
|
51
|
+
# # tests/fixtures/action_text/blobs.yml
|
52
|
+
# second_thumbnail_blob: <%= ActiveStorage::FixtureSet.blob(
|
53
|
+
# filename: "second.svg",
|
54
|
+
# ) %>
|
55
|
+
#
|
56
|
+
# third_thumbnail_blob: <%= ActiveStorage::FixtureSet.blob(
|
57
|
+
# filename: "third.svg",
|
58
|
+
# content_type: "image/svg+xml",
|
59
|
+
# service_name: "public"
|
60
|
+
# ) %>
|
61
|
+
#
|
62
|
+
def self.blob(filename:, **attributes)
|
63
|
+
new.prepare Blob.new(filename: filename, key: generate_unique_secure_token), **attributes
|
64
|
+
end
|
65
|
+
|
66
|
+
def prepare(instance, **attributes)
|
67
|
+
io = file_fixture(instance.filename.to_s).open
|
68
|
+
instance.unfurl(io)
|
69
|
+
instance.assign_attributes(attributes)
|
70
|
+
instance.upload_without_unfurling(io)
|
71
|
+
|
72
|
+
instance.attributes.transform_values { |value| value.is_a?(Hash) ? value.to_json : value }.compact.to_json
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -1,15 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveStorage
|
4
|
-
# Returns the version of
|
4
|
+
# Returns the currently loaded version of Active Storage as a +Gem::Version+.
|
5
5
|
def self.gem_version
|
6
6
|
Gem::Version.new VERSION::STRING
|
7
7
|
end
|
8
8
|
|
9
9
|
module VERSION
|
10
|
-
MAJOR =
|
10
|
+
MAJOR = 7
|
11
11
|
MINOR = 1
|
12
|
-
TINY =
|
12
|
+
TINY = 0
|
13
13
|
PRE = nil
|
14
14
|
|
15
15
|
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
|
@@ -9,34 +9,46 @@ module ActiveStorage
|
|
9
9
|
message += " (checksum: #{event.payload[:checksum]})" if event.payload[:checksum]
|
10
10
|
info event, color(message, GREEN)
|
11
11
|
end
|
12
|
+
subscribe_log_level :service_upload, :info
|
12
13
|
|
13
14
|
def service_download(event)
|
14
15
|
info event, color("Downloaded file from key: #{key_in(event)}", BLUE)
|
15
16
|
end
|
17
|
+
subscribe_log_level :service_download, :info
|
16
18
|
|
17
19
|
alias_method :service_streaming_download, :service_download
|
18
20
|
|
21
|
+
def preview(event)
|
22
|
+
info event, color("Previewed file from key: #{key_in(event)}", BLUE)
|
23
|
+
end
|
24
|
+
subscribe_log_level :preview, :info
|
25
|
+
|
19
26
|
def service_delete(event)
|
20
27
|
info event, color("Deleted file from key: #{key_in(event)}", RED)
|
21
28
|
end
|
29
|
+
subscribe_log_level :service_delete, :info
|
22
30
|
|
23
31
|
def service_delete_prefixed(event)
|
24
32
|
info event, color("Deleted files by key prefix: #{event.payload[:prefix]}", RED)
|
25
33
|
end
|
34
|
+
subscribe_log_level :service_delete_prefixed, :info
|
26
35
|
|
27
36
|
def service_exist(event)
|
28
37
|
debug event, color("Checked if file exists at key: #{key_in(event)} (#{event.payload[:exist] ? "yes" : "no"})", BLUE)
|
29
38
|
end
|
39
|
+
subscribe_log_level :service_exist, :debug
|
30
40
|
|
31
41
|
def service_url(event)
|
32
42
|
debug event, color("Generated URL for file at key: #{key_in(event)} (#{event.payload[:url]})", BLUE)
|
33
43
|
end
|
44
|
+
subscribe_log_level :service_url, :debug
|
34
45
|
|
35
46
|
def service_mirror(event)
|
36
47
|
message = "Mirrored file at key: #{key_in(event)}"
|
37
48
|
message += " (checksum: #{event.payload[:checksum]})" if event.payload[:checksum]
|
38
49
|
debug event, color(message, GREEN)
|
39
50
|
end
|
51
|
+
subscribe_log_level :service_mirror, :debug
|
40
52
|
|
41
53
|
def logger
|
42
54
|
ActiveStorage.logger
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveStorage
|
4
|
+
# = Active Storage \Previewer
|
5
|
+
#
|
4
6
|
# This is an abstract base class for previewers, which generate images from blobs. See
|
5
7
|
# ActiveStorage::Previewer::MuPDFPreviewer and ActiveStorage::Previewer::VideoPreviewer for
|
6
8
|
# examples of concrete subclasses.
|
@@ -26,7 +28,7 @@ module ActiveStorage
|
|
26
28
|
|
27
29
|
private
|
28
30
|
# Downloads the blob to a tempfile on disk. Yields the tempfile.
|
29
|
-
def download_blob_to_tempfile(&block)
|
31
|
+
def download_blob_to_tempfile(&block) # :doc:
|
30
32
|
blob.open tmpdir: tmpdir, &block
|
31
33
|
end
|
32
34
|
|
@@ -44,7 +46,7 @@ module ActiveStorage
|
|
44
46
|
# end
|
45
47
|
#
|
46
48
|
# The output tempfile is opened in the directory returned by #tmpdir.
|
47
|
-
def draw(*argv)
|
49
|
+
def draw(*argv) # :doc:
|
48
50
|
open_tempfile do |file|
|
49
51
|
instrument :preview, key: blob.key do
|
50
52
|
capture(*argv, to: file)
|
@@ -65,7 +67,12 @@ module ActiveStorage
|
|
65
67
|
end
|
66
68
|
|
67
69
|
def instrument(operation, payload = {}, &block)
|
68
|
-
ActiveSupport::Notifications.instrument "#{operation}.active_storage", payload, &block
|
70
|
+
ActiveSupport::Notifications.instrument "#{operation}.active_storage", payload.merge(service: service_name), &block
|
71
|
+
end
|
72
|
+
|
73
|
+
def service_name
|
74
|
+
# ActiveStorage::Service::DiskService => Disk
|
75
|
+
blob.service.class.to_s.split("::").third.remove("Service")
|
69
76
|
end
|
70
77
|
|
71
78
|
def capture(*argv, to:)
|
@@ -83,11 +90,11 @@ module ActiveStorage
|
|
83
90
|
to.rewind
|
84
91
|
end
|
85
92
|
|
86
|
-
def logger
|
93
|
+
def logger # :doc:
|
87
94
|
ActiveStorage.logger
|
88
95
|
end
|
89
96
|
|
90
|
-
def tmpdir
|
97
|
+
def tmpdir # :doc:
|
91
98
|
Dir.tmpdir
|
92
99
|
end
|
93
100
|
end
|
@@ -2,9 +2,19 @@
|
|
2
2
|
|
3
3
|
module ActiveStorage
|
4
4
|
module Reflection
|
5
|
+
class HasAttachedReflection < ActiveRecord::Reflection::MacroReflection # :nodoc:
|
6
|
+
def variant(name, transformations)
|
7
|
+
named_variants[name] = NamedVariant.new(transformations)
|
8
|
+
end
|
9
|
+
|
10
|
+
def named_variants
|
11
|
+
@named_variants ||= {}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
5
15
|
# Holds all the metadata about a has_one_attached attachment as it was
|
6
16
|
# specified in the Active Record class.
|
7
|
-
class HasOneAttachedReflection <
|
17
|
+
class HasOneAttachedReflection < HasAttachedReflection # :nodoc:
|
8
18
|
def macro
|
9
19
|
:has_one_attached
|
10
20
|
end
|
@@ -12,7 +22,7 @@ module ActiveStorage
|
|
12
22
|
|
13
23
|
# Holds all the metadata about a has_many_attached attachment as it was
|
14
24
|
# specified in the Active Record class.
|
15
|
-
class HasManyAttachedReflection <
|
25
|
+
class HasManyAttachedReflection < HasAttachedReflection # :nodoc:
|
16
26
|
def macro
|
17
27
|
:has_many_attached
|
18
28
|
end
|
@@ -1,12 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
gem "azure-storage-blob", ">=
|
3
|
+
gem "azure-storage-blob", ">= 2.0"
|
4
4
|
|
5
5
|
require "active_support/core_ext/numeric/bytes"
|
6
6
|
require "azure/storage/blob"
|
7
7
|
require "azure/storage/common/core/auth/shared_access_signature"
|
8
8
|
|
9
9
|
module ActiveStorage
|
10
|
+
# = Active Storage \Azure Storage \Service
|
11
|
+
#
|
10
12
|
# Wraps the Microsoft Azure Storage Blob Service as an Active Storage service.
|
11
13
|
# See ActiveStorage::Service for the generic API documentation that applies to all services.
|
12
14
|
class Service::AzureStorageService < Service
|
@@ -19,12 +21,12 @@ module ActiveStorage
|
|
19
21
|
@public = public
|
20
22
|
end
|
21
23
|
|
22
|
-
def upload(key, io, checksum: nil, filename: nil, content_type: nil, disposition: nil, **)
|
24
|
+
def upload(key, io, checksum: nil, filename: nil, content_type: nil, disposition: nil, custom_metadata: {}, **)
|
23
25
|
instrument :upload, key: key, checksum: checksum do
|
24
26
|
handle_errors do
|
25
27
|
content_disposition = content_disposition_with(filename: filename, type: disposition) if disposition && filename
|
26
28
|
|
27
|
-
client.create_block_blob(container, key, IO.try_convert(io) || io, content_md5: checksum, content_type: content_type, content_disposition: content_disposition)
|
29
|
+
client.create_block_blob(container, key, IO.try_convert(io) || io, content_md5: checksum, content_type: content_type, content_disposition: content_disposition, metadata: custom_metadata)
|
28
30
|
end
|
29
31
|
end
|
30
32
|
end
|
@@ -86,7 +88,7 @@ module ActiveStorage
|
|
86
88
|
end
|
87
89
|
end
|
88
90
|
|
89
|
-
def url_for_direct_upload(key, expires_in:, content_type:, content_length:, checksum:)
|
91
|
+
def url_for_direct_upload(key, expires_in:, content_type:, content_length:, checksum:, custom_metadata: {})
|
90
92
|
instrument :url, key: key do |payload|
|
91
93
|
generated_url = signer.signed_uri(
|
92
94
|
uri_for(key), false,
|
@@ -101,10 +103,28 @@ module ActiveStorage
|
|
101
103
|
end
|
102
104
|
end
|
103
105
|
|
104
|
-
def headers_for_direct_upload(key, content_type:, checksum:, filename: nil, disposition: nil, **)
|
106
|
+
def headers_for_direct_upload(key, content_type:, checksum:, filename: nil, disposition: nil, custom_metadata: {}, **)
|
105
107
|
content_disposition = content_disposition_with(type: disposition, filename: filename) if filename
|
106
108
|
|
107
|
-
{ "Content-Type" => content_type, "Content-MD5" => checksum, "x-ms-blob-content-disposition" => content_disposition, "x-ms-blob-type" => "BlockBlob" }
|
109
|
+
{ "Content-Type" => content_type, "Content-MD5" => checksum, "x-ms-blob-content-disposition" => content_disposition, "x-ms-blob-type" => "BlockBlob", **custom_metadata_headers(custom_metadata) }
|
110
|
+
end
|
111
|
+
|
112
|
+
def compose(source_keys, destination_key, filename: nil, content_type: nil, disposition: nil, custom_metadata: {})
|
113
|
+
content_disposition = content_disposition_with(type: disposition, filename: filename) if disposition && filename
|
114
|
+
|
115
|
+
client.create_append_blob(
|
116
|
+
container,
|
117
|
+
destination_key,
|
118
|
+
content_type: content_type,
|
119
|
+
content_disposition: content_disposition,
|
120
|
+
metadata: custom_metadata,
|
121
|
+
).tap do |blob|
|
122
|
+
source_keys.each do |source_key|
|
123
|
+
stream(source_key) do |chunk|
|
124
|
+
client.append_blob_block(container, blob.name, chunk)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
108
128
|
end
|
109
129
|
|
110
130
|
private
|
@@ -166,5 +186,9 @@ module ActiveStorage
|
|
166
186
|
raise
|
167
187
|
end
|
168
188
|
end
|
189
|
+
|
190
|
+
def custom_metadata_headers(metadata)
|
191
|
+
metadata.transform_keys { |key| "x-ms-meta-#{key}" }
|
192
|
+
end
|
169
193
|
end
|
170
194
|
end
|
@@ -2,14 +2,16 @@
|
|
2
2
|
|
3
3
|
require "fileutils"
|
4
4
|
require "pathname"
|
5
|
-
require "
|
5
|
+
require "openssl"
|
6
6
|
require "active_support/core_ext/numeric/bytes"
|
7
7
|
|
8
8
|
module ActiveStorage
|
9
|
+
# = Active Storage \Disk \Service
|
10
|
+
#
|
9
11
|
# Wraps a local disk path as an Active Storage service. See ActiveStorage::Service for the generic API
|
10
12
|
# documentation that applies to all services.
|
11
13
|
class Service::DiskService < Service
|
12
|
-
|
14
|
+
attr_accessor :root
|
13
15
|
|
14
16
|
def initialize(root:, public: false, **options)
|
15
17
|
@root = root
|
@@ -72,7 +74,7 @@ module ActiveStorage
|
|
72
74
|
end
|
73
75
|
end
|
74
76
|
|
75
|
-
def url_for_direct_upload(key, expires_in:, content_type:, content_length:, checksum:)
|
77
|
+
def url_for_direct_upload(key, expires_in:, content_type:, content_length:, checksum:, custom_metadata: {})
|
76
78
|
instrument :url, key: key do |payload|
|
77
79
|
verified_token_with_expiration = ActiveStorage.verifier.generate(
|
78
80
|
{
|
@@ -86,11 +88,9 @@ module ActiveStorage
|
|
86
88
|
purpose: :blob_token
|
87
89
|
)
|
88
90
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
generated_url
|
91
|
+
url_helpers.update_rails_disk_service_url(verified_token_with_expiration, url_options).tap do |generated_url|
|
92
|
+
payload[:url] = generated_url
|
93
|
+
end
|
94
94
|
end
|
95
95
|
end
|
96
96
|
|
@@ -98,10 +98,20 @@ module ActiveStorage
|
|
98
98
|
{ "Content-Type" => content_type }
|
99
99
|
end
|
100
100
|
|
101
|
-
def path_for(key)
|
101
|
+
def path_for(key) # :nodoc:
|
102
102
|
File.join root, folder_for(key), key
|
103
103
|
end
|
104
104
|
|
105
|
+
def compose(source_keys, destination_key, **)
|
106
|
+
File.open(make_path_for(destination_key), "w") do |destination_file|
|
107
|
+
source_keys.each do |source_key|
|
108
|
+
File.open(path_for(source_key), "rb") do |source_file|
|
109
|
+
IO.copy_stream(source_file, destination_file)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
105
115
|
private
|
106
116
|
def private_url(key, expires_in:, filename:, content_type:, disposition:, **)
|
107
117
|
generate_url(key, expires_in: expires_in, filename: filename, content_type: content_type, disposition: disposition)
|
@@ -124,14 +134,11 @@ module ActiveStorage
|
|
124
134
|
purpose: :blob_key
|
125
135
|
)
|
126
136
|
|
127
|
-
|
137
|
+
if url_options.blank?
|
138
|
+
raise ArgumentError, "Cannot generate URL for #{filename} using Disk service, please set ActiveStorage::Current.url_options."
|
139
|
+
end
|
128
140
|
|
129
|
-
url_helpers.rails_disk_service_url(verified_key_with_expiration,
|
130
|
-
protocol: current_uri.scheme,
|
131
|
-
host: current_uri.host,
|
132
|
-
port: current_uri.port,
|
133
|
-
filename: filename
|
134
|
-
)
|
141
|
+
url_helpers.rails_disk_service_url(verified_key_with_expiration, filename: filename, **url_options)
|
135
142
|
end
|
136
143
|
|
137
144
|
|
@@ -154,7 +161,7 @@ module ActiveStorage
|
|
154
161
|
end
|
155
162
|
|
156
163
|
def ensure_integrity_of(key, checksum)
|
157
|
-
unless Digest::MD5.file(path_for(key)).base64digest == checksum
|
164
|
+
unless OpenSSL::Digest::MD5.file(path_for(key)).base64digest == checksum
|
158
165
|
delete key
|
159
166
|
raise ActiveStorage::IntegrityError
|
160
167
|
end
|
@@ -164,8 +171,8 @@ module ActiveStorage
|
|
164
171
|
@url_helpers ||= Rails.application.routes.url_helpers
|
165
172
|
end
|
166
173
|
|
167
|
-
def
|
168
|
-
ActiveStorage::Current.
|
174
|
+
def url_options
|
175
|
+
ActiveStorage::Current.url_options
|
169
176
|
end
|
170
177
|
end
|
171
178
|
end
|