activestorage 8.0.2.1 → 8.1.0.beta1

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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +40 -54
  3. data/README.md +6 -3
  4. data/app/assets/javascripts/activestorage.esm.js +37 -1
  5. data/app/assets/javascripts/activestorage.js +37 -1
  6. data/app/controllers/active_storage/disk_controller.rb +2 -2
  7. data/app/javascript/activestorage/direct_upload_controller.js +48 -1
  8. data/app/models/active_storage/blob/representable.rb +66 -0
  9. data/app/models/active_storage/blob.rb +1 -1
  10. data/app/models/active_storage/filename.rb +1 -0
  11. data/app/models/active_storage/variant.rb +7 -7
  12. data/app/models/active_storage/variation.rb +1 -1
  13. data/lib/active_storage/analyzer/image_analyzer/image_magick.rb +7 -11
  14. data/lib/active_storage/analyzer/image_analyzer/vips.rb +10 -11
  15. data/lib/active_storage/analyzer/image_analyzer.rb +5 -0
  16. data/lib/active_storage/attached/model.rb +4 -4
  17. data/lib/active_storage/attached.rb +0 -1
  18. data/lib/active_storage/downloader.rb +1 -1
  19. data/lib/active_storage/engine.rb +48 -10
  20. data/lib/active_storage/fixture_set.rb +1 -1
  21. data/lib/active_storage/gem_version.rb +3 -3
  22. data/lib/active_storage/service/configurator.rb +6 -0
  23. data/lib/active_storage/service/disk_service.rb +1 -1
  24. data/lib/active_storage/service/gcs_service.rb +10 -2
  25. data/lib/active_storage/service/mirror_service.rb +1 -1
  26. data/lib/active_storage/service/registry.rb +6 -0
  27. data/lib/active_storage/service/s3_service.rb +19 -4
  28. data/lib/active_storage/service.rb +4 -1
  29. data/lib/active_storage/transformers/image_magick.rb +72 -0
  30. data/lib/active_storage/transformers/image_processing_transformer.rb +5 -67
  31. data/lib/active_storage/transformers/vips.rb +11 -0
  32. data/lib/active_storage.rb +13 -0
  33. metadata +14 -13
  34. data/lib/active_storage/service/azure_storage_service.rb +0 -201
@@ -1,201 +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
- ActiveStorage.deprecator.warn <<~MSG.squish
19
- `ActiveStorage::Service::AzureStorageService` is deprecated and will be
20
- removed in Rails 8.1.
21
- Please try the `azure-blob` gem instead.
22
- This gem is not maintained by the Rails team, so please test your applications before deploying to production.
23
- MSG
24
-
25
- @client = Azure::Storage::Blob::BlobService.create(storage_account_name: storage_account_name, storage_access_key: storage_access_key, **options)
26
- @signer = Azure::Storage::Common::Core::Auth::SharedAccessSignature.new(storage_account_name, storage_access_key)
27
- @container = container
28
- @public = public
29
- end
30
-
31
- def upload(key, io, checksum: nil, filename: nil, content_type: nil, disposition: nil, custom_metadata: {}, **)
32
- instrument :upload, key: key, checksum: checksum do
33
- handle_errors do
34
- content_disposition = content_disposition_with(filename: filename, type: disposition) if disposition && filename
35
-
36
- 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)
37
- end
38
- end
39
- end
40
-
41
- def download(key, &block)
42
- if block_given?
43
- instrument :streaming_download, key: key do
44
- stream(key, &block)
45
- end
46
- else
47
- instrument :download, key: key do
48
- handle_errors do
49
- _, io = client.get_blob(container, key)
50
- io.force_encoding(Encoding::BINARY)
51
- end
52
- end
53
- end
54
- end
55
-
56
- def download_chunk(key, range)
57
- instrument :download_chunk, key: key, range: range do
58
- handle_errors do
59
- _, io = client.get_blob(container, key, start_range: range.begin, end_range: range.exclude_end? ? range.end - 1 : range.end)
60
- io.force_encoding(Encoding::BINARY)
61
- end
62
- end
63
- end
64
-
65
- def delete(key)
66
- instrument :delete, key: key do
67
- client.delete_blob(container, key)
68
- rescue Azure::Core::Http::HTTPError => e
69
- raise unless e.type == "BlobNotFound"
70
- # Ignore files already deleted
71
- end
72
- end
73
-
74
- def delete_prefixed(prefix)
75
- instrument :delete_prefixed, prefix: prefix do
76
- marker = nil
77
-
78
- loop do
79
- results = client.list_blobs(container, prefix: prefix, marker: marker)
80
-
81
- results.each do |blob|
82
- client.delete_blob(container, blob.name)
83
- end
84
-
85
- break unless marker = results.continuation_token.presence
86
- end
87
- end
88
- end
89
-
90
- def exist?(key)
91
- instrument :exist, key: key do |payload|
92
- answer = blob_for(key).present?
93
- payload[:exist] = answer
94
- answer
95
- end
96
- end
97
-
98
- def url_for_direct_upload(key, expires_in:, content_type:, content_length:, checksum:, custom_metadata: {})
99
- instrument :url, key: key do |payload|
100
- generated_url = signer.signed_uri(
101
- uri_for(key), false,
102
- service: "b",
103
- permissions: "rw",
104
- expiry: format_expiry(expires_in)
105
- ).to_s
106
-
107
- payload[:url] = generated_url
108
-
109
- generated_url
110
- end
111
- end
112
-
113
- def headers_for_direct_upload(key, content_type:, checksum:, filename: nil, disposition: nil, custom_metadata: {}, **)
114
- content_disposition = content_disposition_with(type: disposition, filename: filename) if filename
115
-
116
- { "Content-Type" => content_type, "Content-MD5" => checksum, "x-ms-blob-content-disposition" => content_disposition, "x-ms-blob-type" => "BlockBlob", **custom_metadata_headers(custom_metadata) }
117
- end
118
-
119
- def compose(source_keys, destination_key, filename: nil, content_type: nil, disposition: nil, custom_metadata: {})
120
- content_disposition = content_disposition_with(type: disposition, filename: filename) if disposition && filename
121
-
122
- client.create_append_blob(
123
- container,
124
- destination_key,
125
- content_type: content_type,
126
- content_disposition: content_disposition,
127
- metadata: custom_metadata,
128
- ).tap do |blob|
129
- source_keys.each do |source_key|
130
- stream(source_key) do |chunk|
131
- client.append_blob_block(container, blob.name, chunk)
132
- end
133
- end
134
- end
135
- end
136
-
137
- private
138
- def private_url(key, expires_in:, filename:, disposition:, content_type:, **)
139
- signer.signed_uri(
140
- uri_for(key), false,
141
- service: "b",
142
- permissions: "r",
143
- expiry: format_expiry(expires_in),
144
- content_disposition: content_disposition_with(type: disposition, filename: filename),
145
- content_type: content_type
146
- ).to_s
147
- end
148
-
149
- def public_url(key, **)
150
- uri_for(key).to_s
151
- end
152
-
153
-
154
- def uri_for(key)
155
- client.generate_uri("#{container}/#{key}")
156
- end
157
-
158
- def blob_for(key)
159
- client.get_blob_properties(container, key)
160
- rescue Azure::Core::Http::HTTPError
161
- false
162
- end
163
-
164
- def format_expiry(expires_in)
165
- expires_in ? Time.now.utc.advance(seconds: expires_in).iso8601 : nil
166
- end
167
-
168
- # Reads the object for the given key in chunks, yielding each to the block.
169
- def stream(key)
170
- blob = blob_for(key)
171
-
172
- chunk_size = 5.megabytes
173
- offset = 0
174
-
175
- raise ActiveStorage::FileNotFoundError unless blob.present?
176
-
177
- while offset < blob.properties[:content_length]
178
- _, chunk = client.get_blob(container, key, start_range: offset, end_range: offset + chunk_size - 1)
179
- yield chunk.force_encoding(Encoding::BINARY)
180
- offset += chunk_size
181
- end
182
- end
183
-
184
- def handle_errors
185
- yield
186
- rescue Azure::Core::Http::HTTPError => e
187
- case e.type
188
- when "BlobNotFound"
189
- raise ActiveStorage::FileNotFoundError
190
- when "Md5Mismatch"
191
- raise ActiveStorage::IntegrityError
192
- else
193
- raise
194
- end
195
- end
196
-
197
- def custom_metadata_headers(metadata)
198
- metadata.transform_keys { |key| "x-ms-meta-#{key}" }
199
- end
200
- end
201
- end