activestorage 7.2.2.1 → 8.1.3

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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +126 -55
  3. data/README.md +8 -5
  4. data/app/assets/javascripts/activestorage.esm.js +38 -2
  5. data/app/assets/javascripts/activestorage.js +38 -1
  6. data/app/controllers/active_storage/direct_uploads_controller.rb +1 -1
  7. data/app/controllers/active_storage/disk_controller.rb +6 -2
  8. data/app/controllers/concerns/active_storage/streaming.rb +17 -1
  9. data/app/javascript/activestorage/direct_upload_controller.js +48 -1
  10. data/app/javascript/activestorage/index.js +2 -1
  11. data/app/models/active_storage/blob/representable.rb +71 -5
  12. data/app/models/active_storage/blob.rb +25 -21
  13. data/app/models/active_storage/filename.rb +2 -1
  14. data/app/models/active_storage/variant.rb +12 -12
  15. data/app/models/active_storage/variation.rb +1 -1
  16. data/lib/active_storage/analyzer/image_analyzer/image_magick.rb +11 -4
  17. data/lib/active_storage/analyzer/image_analyzer/vips.rb +23 -5
  18. data/lib/active_storage/analyzer/image_analyzer.rb +5 -0
  19. data/lib/active_storage/attached/changes/create_one.rb +1 -1
  20. data/lib/active_storage/attached/model.rb +41 -18
  21. data/lib/active_storage/attached.rb +0 -1
  22. data/lib/active_storage/engine.rb +38 -7
  23. data/lib/active_storage/errors.rb +4 -0
  24. data/lib/active_storage/fixture_set.rb +1 -1
  25. data/lib/active_storage/gem_version.rb +4 -4
  26. data/lib/active_storage/log_subscriber.rb +1 -1
  27. data/lib/active_storage/service/configurator.rb +6 -0
  28. data/lib/active_storage/service/disk_service.rb +46 -2
  29. data/lib/active_storage/service/gcs_service.rb +15 -5
  30. data/lib/active_storage/service/mirror_service.rb +13 -4
  31. data/lib/active_storage/service/registry.rb +6 -0
  32. data/lib/active_storage/service/s3_service.rb +19 -4
  33. data/lib/active_storage/service.rb +5 -1
  34. data/lib/active_storage/structured_event_subscriber.rb +79 -0
  35. data/lib/active_storage/transformers/image_magick.rb +72 -0
  36. data/lib/active_storage/transformers/image_processing_transformer.rb +5 -67
  37. data/lib/active_storage/transformers/null_transformer.rb +12 -0
  38. data/lib/active_storage/transformers/vips.rb +11 -0
  39. data/lib/active_storage.rb +19 -3
  40. metadata +19 -19
  41. data/lib/active_storage/service/azure_storage_service.rb +0 -194
@@ -1,194 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- gem "azure-storage-blob", ">= 2.0"
4
-
5
- require "active_support/core_ext/numeric/bytes"
6
- require "azure/storage/blob"
7
- require "azure/storage/common/core/auth/shared_access_signature"
8
-
9
- module ActiveStorage
10
- # = Active Storage \Azure Storage \Service
11
- #
12
- # Wraps the Microsoft Azure Storage Blob Service as an Active Storage service.
13
- # See ActiveStorage::Service for the generic API documentation that applies to all services.
14
- class Service::AzureStorageService < Service
15
- attr_reader :client, :container, :signer
16
-
17
- def initialize(storage_account_name:, storage_access_key:, container:, public: false, **options)
18
- @client = Azure::Storage::Blob::BlobService.create(storage_account_name: storage_account_name, storage_access_key: storage_access_key, **options)
19
- @signer = Azure::Storage::Common::Core::Auth::SharedAccessSignature.new(storage_account_name, storage_access_key)
20
- @container = container
21
- @public = public
22
- end
23
-
24
- def upload(key, io, checksum: nil, filename: nil, content_type: nil, disposition: nil, custom_metadata: {}, **)
25
- instrument :upload, key: key, checksum: checksum do
26
- handle_errors do
27
- content_disposition = content_disposition_with(filename: filename, type: disposition) if disposition && filename
28
-
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)
30
- end
31
- end
32
- end
33
-
34
- def download(key, &block)
35
- if block_given?
36
- instrument :streaming_download, key: key do
37
- stream(key, &block)
38
- end
39
- else
40
- instrument :download, key: key do
41
- handle_errors do
42
- _, io = client.get_blob(container, key)
43
- io.force_encoding(Encoding::BINARY)
44
- end
45
- end
46
- end
47
- end
48
-
49
- def download_chunk(key, range)
50
- instrument :download_chunk, key: key, range: range do
51
- handle_errors do
52
- _, io = client.get_blob(container, key, start_range: range.begin, end_range: range.exclude_end? ? range.end - 1 : range.end)
53
- io.force_encoding(Encoding::BINARY)
54
- end
55
- end
56
- end
57
-
58
- def delete(key)
59
- instrument :delete, key: key do
60
- client.delete_blob(container, key)
61
- rescue Azure::Core::Http::HTTPError => e
62
- raise unless e.type == "BlobNotFound"
63
- # Ignore files already deleted
64
- end
65
- end
66
-
67
- def delete_prefixed(prefix)
68
- instrument :delete_prefixed, prefix: prefix do
69
- marker = nil
70
-
71
- loop do
72
- results = client.list_blobs(container, prefix: prefix, marker: marker)
73
-
74
- results.each do |blob|
75
- client.delete_blob(container, blob.name)
76
- end
77
-
78
- break unless marker = results.continuation_token.presence
79
- end
80
- end
81
- end
82
-
83
- def exist?(key)
84
- instrument :exist, key: key do |payload|
85
- answer = blob_for(key).present?
86
- payload[:exist] = answer
87
- answer
88
- end
89
- end
90
-
91
- def url_for_direct_upload(key, expires_in:, content_type:, content_length:, checksum:, custom_metadata: {})
92
- instrument :url, key: key do |payload|
93
- generated_url = signer.signed_uri(
94
- uri_for(key), false,
95
- service: "b",
96
- permissions: "rw",
97
- expiry: format_expiry(expires_in)
98
- ).to_s
99
-
100
- payload[:url] = generated_url
101
-
102
- generated_url
103
- end
104
- end
105
-
106
- def headers_for_direct_upload(key, content_type:, checksum:, filename: nil, disposition: nil, custom_metadata: {}, **)
107
- content_disposition = content_disposition_with(type: disposition, filename: filename) if filename
108
-
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
128
- end
129
-
130
- private
131
- def private_url(key, expires_in:, filename:, disposition:, content_type:, **)
132
- signer.signed_uri(
133
- uri_for(key), false,
134
- service: "b",
135
- permissions: "r",
136
- expiry: format_expiry(expires_in),
137
- content_disposition: content_disposition_with(type: disposition, filename: filename),
138
- content_type: content_type
139
- ).to_s
140
- end
141
-
142
- def public_url(key, **)
143
- uri_for(key).to_s
144
- end
145
-
146
-
147
- def uri_for(key)
148
- client.generate_uri("#{container}/#{key}")
149
- end
150
-
151
- def blob_for(key)
152
- client.get_blob_properties(container, key)
153
- rescue Azure::Core::Http::HTTPError
154
- false
155
- end
156
-
157
- def format_expiry(expires_in)
158
- expires_in ? Time.now.utc.advance(seconds: expires_in).iso8601 : nil
159
- end
160
-
161
- # Reads the object for the given key in chunks, yielding each to the block.
162
- def stream(key)
163
- blob = blob_for(key)
164
-
165
- chunk_size = 5.megabytes
166
- offset = 0
167
-
168
- raise ActiveStorage::FileNotFoundError unless blob.present?
169
-
170
- while offset < blob.properties[:content_length]
171
- _, chunk = client.get_blob(container, key, start_range: offset, end_range: offset + chunk_size - 1)
172
- yield chunk.force_encoding(Encoding::BINARY)
173
- offset += chunk_size
174
- end
175
- end
176
-
177
- def handle_errors
178
- yield
179
- rescue Azure::Core::Http::HTTPError => e
180
- case e.type
181
- when "BlobNotFound"
182
- raise ActiveStorage::FileNotFoundError
183
- when "Md5Mismatch"
184
- raise ActiveStorage::IntegrityError
185
- else
186
- raise
187
- end
188
- end
189
-
190
- def custom_metadata_headers(metadata)
191
- metadata.transform_keys { |key| "x-ms-meta-#{key}" }
192
- end
193
- end
194
- end