activestorage_saas 5.2.5.2 → 7.2.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.
- checksums.yaml +4 -4
- data/AGENTS.md +260 -0
- data/CHANGELOG.md +12 -0
- data/COVERAGE.md +64 -0
- data/Gemfile +8 -4
- data/README.md +206 -17
- data/lib/active_storage/service/saas_service.rb +15 -10
- data/lib/active_storage_saas/blob_model_mixin.rb +48 -0
- data/lib/active_storage_saas/direct_uploads_controller_mixin.rb +31 -0
- data/lib/active_storage_saas/engine.rb +26 -5
- data/lib/active_storage_saas/routes.rb +3 -3
- data/lib/active_storage_saas/storage_service_configuration_model_mixin.rb +48 -0
- data/lib/active_storage_saas.rb +4 -2
- data/lib/generators/active_storage_saas/install/USAGE +5 -0
- data/lib/generators/active_storage_saas/install/install_generator.rb +19 -0
- data/lib/generators/active_storage_saas/install/templates/config/initializers/active_storage_saas.rb +6 -0
- metadata +13 -21
- data/.rspec +0 -3
- data/.rubocop.yml +0 -17
- data/Gemfile.lock +0 -112
- data/Rakefile +0 -12
- data/activestorage_saas.gemspec +0 -33
- data/app/controller/active_storage_saas/direct_uploads_controller.rb +0 -28
- data/app/javascript/active_storage_saas/direct_upload_controller/blob_record.js +0 -73
- data/app/javascript/active_storage_saas/direct_upload_controller/blob_upload.js +0 -45
- data/app/javascript/active_storage_saas/direct_upload_controller/direct_upload.js +0 -48
- data/app/javascript/active_storage_saas/direct_upload_controller/file_checksum.js +0 -53
- data/app/javascript/active_storage_saas/direct_upload_controller/helpers.js +0 -51
- data/app/javascript/active_storage_saas/direct_upload_controller.js +0 -78
- data/app/models/tenant_storage_service.rb +0 -5
- data/db/migrate/001_activestorage_saas_tables.rb +0 -17
- data/lib/active_storage_saas/blob_patch.rb +0 -51
- data/sig/activestorage_saas.rbs +0 -4
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require 'active_storage/service/saas_service'
|
|
2
|
+
|
|
3
|
+
module ActiveStorageSaas
|
|
4
|
+
module BlobModelMixin
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
included do
|
|
8
|
+
prepend InstanceMethods
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
prepended do
|
|
12
|
+
prepend InstanceMethods
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
module InstanceMethods
|
|
16
|
+
extend ActiveSupport::Concern
|
|
17
|
+
|
|
18
|
+
prepended do
|
|
19
|
+
redefine_method :service do
|
|
20
|
+
@service ||= begin
|
|
21
|
+
raise KeyError, "storage service name should not be 'saas'" if service_name.to_s == 'saas'
|
|
22
|
+
|
|
23
|
+
services.fetch(service_name) { |_| ActiveStorageSaas.service_resolver.call(self) } || global_service
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
validate on: :save do
|
|
28
|
+
errors.add(:service_name, :invalid) if service_name.to_s == 'saas'
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def global_service
|
|
35
|
+
self.class.service
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def analyzer_class
|
|
39
|
+
analyzers = service.class.respond_to?(:analyzers) ? service.class.analyzers : ActiveStorage.analyzers
|
|
40
|
+
analyzers.detect { |klass| klass.accept?(self) } || ActiveStorage::Analyzer::NullAnalyzer
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def validate_service_name_in_services
|
|
44
|
+
ActiveStorageSaas.service_name_validator.call(service_name) || super
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module ActiveStorageSaas
|
|
2
|
+
module DirectUploadsControllerMixin
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
included do
|
|
6
|
+
prepend InstanceMethods
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
prepended do
|
|
10
|
+
prepend InstanceMethods
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
module InstanceMethods
|
|
14
|
+
def create
|
|
15
|
+
blob = ActiveStorage::Blob.create_before_direct_upload!(**blob_args)
|
|
16
|
+
render json: direct_upload_json(blob)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def callback
|
|
20
|
+
ActiveStorageSaas.direct_upload_callback.call(self)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def blob_args
|
|
26
|
+
super.merge(ActiveStorageSaas.direct_upload_extra_blob_args.call(self))
|
|
27
|
+
.merge(service_name: ActiveStorageSaas.service_name_converter.call(self))
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -1,17 +1,38 @@
|
|
|
1
|
+
require 'active_storage_saas/blob_model_mixin'
|
|
2
|
+
require 'active_storage_saas/direct_uploads_controller_mixin'
|
|
3
|
+
require 'active_storage_saas/storage_service_configuration_model_mixin'
|
|
1
4
|
module ActiveStorageSaas
|
|
2
5
|
class Engine < Rails::Engine
|
|
3
|
-
config.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
+
config.generators do |g|
|
|
7
|
+
g.test_framework :rspec
|
|
8
|
+
end
|
|
9
|
+
config.active_storage_saas = ActiveSupport::OrderedOptions.new
|
|
10
|
+
|
|
11
|
+
initializer "active_storage_saas.configs" do
|
|
12
|
+
config.after_initialize do |app|
|
|
13
|
+
default_service_resolver = ->(blob) { StorageServiceConfiguration.from_service_name(blob.service_name)&.to_service }
|
|
14
|
+
default_service_name_converter = ->(controller) { StorageServiceConfiguration.first.to_service_name }
|
|
15
|
+
default_service_name_validator = ->(service_name) { StorageServiceConfiguration.valid_service_name?(service_name) }
|
|
16
|
+
default_direct_upload_extra_blob_args = ->(controller) { { } }
|
|
17
|
+
ActiveStorageSaas.service_resolver = app.config.active_storage_saas.service_resolver || default_service_resolver
|
|
18
|
+
ActiveStorageSaas.service_name_converter = app.config.active_storage_saas.service_name_converter || default_service_name_converter
|
|
19
|
+
ActiveStorageSaas.service_name_validator = app.config.active_storage_saas.service_name_validator || default_service_name_validator
|
|
20
|
+
ActiveStorageSaas.direct_upload_extra_blob_args = app.config.active_storage_saas.direct_upload_extra_blob_args || default_direct_upload_extra_blob_args
|
|
21
|
+
ActiveStorage::Blob # call this class to load mixin
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
config.to_prepare do
|
|
25
|
+
ActiveStorage::DirectUploadsController.include ActiveStorageSaas::DirectUploadsControllerMixin
|
|
26
|
+
end
|
|
6
27
|
end
|
|
7
28
|
|
|
8
29
|
config.to_prepare do
|
|
9
30
|
ActionDispatch::Routing::Mapper.include Routes
|
|
10
31
|
end
|
|
11
32
|
|
|
12
|
-
initializer '
|
|
33
|
+
initializer 'active_storage_saas.load_mixins' do
|
|
13
34
|
ActiveSupport.on_load(:active_storage_blob) do
|
|
14
|
-
include ActiveStorageSaas::
|
|
35
|
+
include ActiveStorageSaas::BlobModelMixin
|
|
15
36
|
end
|
|
16
37
|
end
|
|
17
38
|
end
|
|
@@ -3,9 +3,9 @@ module ActiveStorageSaas
|
|
|
3
3
|
# rubocop: disable Layout/LineLength
|
|
4
4
|
def draw_active_storage_saas_routes(
|
|
5
5
|
prefix: '/rails/active_storage',
|
|
6
|
-
blobs_controller: '
|
|
7
|
-
representations_controller: '
|
|
8
|
-
disk_controller: '
|
|
6
|
+
blobs_controller: 'active_storage_saas/blobs',
|
|
7
|
+
representations_controller: 'active_storage_saas/representations',
|
|
8
|
+
disk_controller: 'active_storage_saas/disk',
|
|
9
9
|
direct_uploads_controller: 'active_storage_saas/direct_uploads',
|
|
10
10
|
**option_overrides
|
|
11
11
|
)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
module ActiveStorageSaas
|
|
2
|
+
module StorageServiceConfigurationMixin
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
included do
|
|
6
|
+
prepend InstanceMethods
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
prepended do
|
|
10
|
+
prepend InstanceMethods
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
module InstanceMethods
|
|
14
|
+
extend ActiveSupport::Concern
|
|
15
|
+
|
|
16
|
+
class_methods do
|
|
17
|
+
def service_name_pattern
|
|
18
|
+
/^#{name}:(\d+)$/
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def from_service_name(service_name)
|
|
22
|
+
find_by(id: Regexp.last_match(1)) if service_name =~ service_name_pattern
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def valid_service_name?(service_name)
|
|
26
|
+
service_name_pattern.match?(service_name)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def to_service
|
|
31
|
+
defined_service = ActiveStorage::Blob.services.fetch(service_name)
|
|
32
|
+
klass = defined_service.class
|
|
33
|
+
options = ActiveStorage::Blob.services.send(:configurations).fetch(service_name.to_sym).deep_dup
|
|
34
|
+
options.delete(:service) if service_name == 'amazon'
|
|
35
|
+
options.deep_merge! service_options.deep_symbolize_keys
|
|
36
|
+
klass.new(**options).tap do |instance|
|
|
37
|
+
instance.instance_eval <<~RUBY
|
|
38
|
+
define_singleton_method(:name) { "#{to_service_name}" }
|
|
39
|
+
RUBY
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def to_service_name
|
|
44
|
+
"#{self.class.name}:#{id}"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
data/lib/active_storage_saas.rb
CHANGED
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
module ActiveStorageSaas
|
|
4
4
|
class Error < StandardError; end
|
|
5
5
|
|
|
6
|
-
mattr_accessor :
|
|
6
|
+
mattr_accessor :service_resolver
|
|
7
|
+
mattr_accessor :service_name_converter
|
|
8
|
+
mattr_accessor :service_name_validator
|
|
9
|
+
mattr_accessor :direct_upload_extra_blob_args
|
|
7
10
|
|
|
8
11
|
require 'active_storage_saas/routes'
|
|
9
|
-
require 'active_storage_saas/blob_patch'
|
|
10
12
|
require 'active_storage_saas/engine'
|
|
11
13
|
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module ActiveStorageSaas
|
|
2
|
+
class InstallGenerator < Rails::Generators::Base
|
|
3
|
+
source_root File.expand_path("templates", __dir__)
|
|
4
|
+
class_option :configuration_model, type: :string, default: 'StorageServiceConfiguration'
|
|
5
|
+
|
|
6
|
+
def generate_model
|
|
7
|
+
generate "model", "#{options['configuration_model']} service_name service_options:json"
|
|
8
|
+
inject_into_file "app/models/#{options['configuration_model'].underscore}.rb", after: /^class .+\n/ do <<-'RUBY'
|
|
9
|
+
include ActiveStorageSaas::StorageServiceConfigurationMixin
|
|
10
|
+
|
|
11
|
+
RUBY
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def copy_files
|
|
16
|
+
template 'config/initializers/active_storage_saas.rb'
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
data/lib/generators/active_storage_saas/install/templates/config/initializers/active_storage_saas.rb
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
Rails.application.configure do
|
|
2
|
+
# config.active_storage_saas.service_resolver = ->(blob) { StorageServiceConfiguration.from_service_name(blob.service_name)&.to_service }
|
|
3
|
+
# config.active_storage_saas.service_name_converter = ->(controller) { controller.send(:current_tenant).storage_service&.to_service_name }
|
|
4
|
+
# config.active_storage_saas.service_name_validator = ->(service_name) { StorageServiceConfiguration.valid_service_name?(service_name) }
|
|
5
|
+
# config.active_storage_saas.direct_upload_extra_blob_args = ->(controller) { { tenant: controller.send(:current_tenant) } }
|
|
6
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: activestorage_saas
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 7.2.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- xiaohui
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2025-12-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activestorage
|
|
@@ -16,14 +16,14 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - '='
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version:
|
|
19
|
+
version: 7.2.3
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - '='
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version:
|
|
26
|
+
version: 7.2.3
|
|
27
27
|
description: Each tenant can set its own storage service, ActiveStorage service can
|
|
28
28
|
be dynamically loaded.
|
|
29
29
|
email:
|
|
@@ -32,31 +32,23 @@ executables: []
|
|
|
32
32
|
extensions: []
|
|
33
33
|
extra_rdoc_files: []
|
|
34
34
|
files:
|
|
35
|
-
-
|
|
36
|
-
- ".rubocop.yml"
|
|
35
|
+
- AGENTS.md
|
|
37
36
|
- CHANGELOG.md
|
|
37
|
+
- COVERAGE.md
|
|
38
38
|
- Gemfile
|
|
39
|
-
- Gemfile.lock
|
|
40
39
|
- LICENSE.txt
|
|
41
40
|
- README.md
|
|
42
|
-
- Rakefile
|
|
43
|
-
- activestorage_saas.gemspec
|
|
44
|
-
- app/controller/active_storage_saas/direct_uploads_controller.rb
|
|
45
|
-
- app/javascript/active_storage_saas/direct_upload_controller.js
|
|
46
|
-
- app/javascript/active_storage_saas/direct_upload_controller/blob_record.js
|
|
47
|
-
- app/javascript/active_storage_saas/direct_upload_controller/blob_upload.js
|
|
48
|
-
- app/javascript/active_storage_saas/direct_upload_controller/direct_upload.js
|
|
49
|
-
- app/javascript/active_storage_saas/direct_upload_controller/file_checksum.js
|
|
50
|
-
- app/javascript/active_storage_saas/direct_upload_controller/helpers.js
|
|
51
|
-
- app/models/tenant_storage_service.rb
|
|
52
|
-
- db/migrate/001_activestorage_saas_tables.rb
|
|
53
41
|
- lib/active_storage/service/saas_service.rb
|
|
54
42
|
- lib/active_storage_saas.rb
|
|
55
|
-
- lib/active_storage_saas/
|
|
43
|
+
- lib/active_storage_saas/blob_model_mixin.rb
|
|
44
|
+
- lib/active_storage_saas/direct_uploads_controller_mixin.rb
|
|
56
45
|
- lib/active_storage_saas/engine.rb
|
|
57
46
|
- lib/active_storage_saas/routes.rb
|
|
47
|
+
- lib/active_storage_saas/storage_service_configuration_model_mixin.rb
|
|
58
48
|
- lib/activestorage_saas.rb
|
|
59
|
-
-
|
|
49
|
+
- lib/generators/active_storage_saas/install/USAGE
|
|
50
|
+
- lib/generators/active_storage_saas/install/install_generator.rb
|
|
51
|
+
- lib/generators/active_storage_saas/install/templates/config/initializers/active_storage_saas.rb
|
|
60
52
|
homepage: https://github.com/xiaohui-zhangxh/activestorage_saas
|
|
61
53
|
licenses:
|
|
62
54
|
- MIT
|
|
@@ -79,7 +71,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
79
71
|
- !ruby/object:Gem::Version
|
|
80
72
|
version: '0'
|
|
81
73
|
requirements: []
|
|
82
|
-
rubygems_version: 3.
|
|
74
|
+
rubygems_version: 3.5.16
|
|
83
75
|
signing_key:
|
|
84
76
|
specification_version: 4
|
|
85
77
|
summary: Wraps multi-tenant storage services as ActiveStorage service
|
data/.rspec
DELETED
data/.rubocop.yml
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
AllCops:
|
|
2
|
-
TargetRubyVersion: 2.6
|
|
3
|
-
NewCops: enable
|
|
4
|
-
Style/StringLiterals:
|
|
5
|
-
Enabled: true
|
|
6
|
-
EnforcedStyle: single_quotes
|
|
7
|
-
|
|
8
|
-
Style/StringLiteralsInInterpolation:
|
|
9
|
-
Enabled: true
|
|
10
|
-
EnforcedStyle: double_quotes
|
|
11
|
-
|
|
12
|
-
Layout/LineLength:
|
|
13
|
-
Max: 120
|
|
14
|
-
|
|
15
|
-
Layout/IndentationConsistency:
|
|
16
|
-
Enabled: true
|
|
17
|
-
EnforcedStyle: indented_internal_methods
|
data/Gemfile.lock
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
PATH
|
|
2
|
-
remote: .
|
|
3
|
-
specs:
|
|
4
|
-
activestorage_saas (5.2.5.1)
|
|
5
|
-
activestorage (= 5.2.5)
|
|
6
|
-
|
|
7
|
-
GEM
|
|
8
|
-
remote: https://rubygems.org/
|
|
9
|
-
specs:
|
|
10
|
-
actionpack (5.2.5)
|
|
11
|
-
actionview (= 5.2.5)
|
|
12
|
-
activesupport (= 5.2.5)
|
|
13
|
-
rack (~> 2.0, >= 2.0.8)
|
|
14
|
-
rack-test (>= 0.6.3)
|
|
15
|
-
rails-dom-testing (~> 2.0)
|
|
16
|
-
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
|
17
|
-
actionview (5.2.5)
|
|
18
|
-
activesupport (= 5.2.5)
|
|
19
|
-
builder (~> 3.1)
|
|
20
|
-
erubi (~> 1.4)
|
|
21
|
-
rails-dom-testing (~> 2.0)
|
|
22
|
-
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
|
23
|
-
activemodel (5.2.5)
|
|
24
|
-
activesupport (= 5.2.5)
|
|
25
|
-
activerecord (5.2.5)
|
|
26
|
-
activemodel (= 5.2.5)
|
|
27
|
-
activesupport (= 5.2.5)
|
|
28
|
-
arel (>= 9.0)
|
|
29
|
-
activestorage (5.2.5)
|
|
30
|
-
actionpack (= 5.2.5)
|
|
31
|
-
activerecord (= 5.2.5)
|
|
32
|
-
marcel (~> 1.0.0)
|
|
33
|
-
activesupport (5.2.5)
|
|
34
|
-
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
35
|
-
i18n (>= 0.7, < 2)
|
|
36
|
-
minitest (~> 5.1)
|
|
37
|
-
tzinfo (~> 1.1)
|
|
38
|
-
arel (9.0.0)
|
|
39
|
-
ast (2.4.2)
|
|
40
|
-
builder (3.2.4)
|
|
41
|
-
concurrent-ruby (1.1.10)
|
|
42
|
-
crass (1.0.6)
|
|
43
|
-
diff-lcs (1.5.0)
|
|
44
|
-
erubi (1.11.0)
|
|
45
|
-
i18n (1.12.0)
|
|
46
|
-
concurrent-ruby (~> 1.0)
|
|
47
|
-
loofah (2.18.0)
|
|
48
|
-
crass (~> 1.0.2)
|
|
49
|
-
nokogiri (>= 1.5.9)
|
|
50
|
-
marcel (1.0.2)
|
|
51
|
-
mini_portile2 (2.8.0)
|
|
52
|
-
minitest (5.16.2)
|
|
53
|
-
nokogiri (1.13.8)
|
|
54
|
-
mini_portile2 (~> 2.8.0)
|
|
55
|
-
racc (~> 1.4)
|
|
56
|
-
parallel (1.22.1)
|
|
57
|
-
parser (3.1.1.0)
|
|
58
|
-
ast (~> 2.4.1)
|
|
59
|
-
racc (1.6.0)
|
|
60
|
-
rack (2.2.4)
|
|
61
|
-
rack-test (2.0.2)
|
|
62
|
-
rack (>= 1.3)
|
|
63
|
-
rails-dom-testing (2.0.3)
|
|
64
|
-
activesupport (>= 4.2.0)
|
|
65
|
-
nokogiri (>= 1.6)
|
|
66
|
-
rails-html-sanitizer (1.4.3)
|
|
67
|
-
loofah (~> 2.3)
|
|
68
|
-
rainbow (3.1.1)
|
|
69
|
-
rake (13.0.6)
|
|
70
|
-
regexp_parser (2.5.0)
|
|
71
|
-
rexml (3.2.5)
|
|
72
|
-
rspec (3.11.0)
|
|
73
|
-
rspec-core (~> 3.11.0)
|
|
74
|
-
rspec-expectations (~> 3.11.0)
|
|
75
|
-
rspec-mocks (~> 3.11.0)
|
|
76
|
-
rspec-core (3.11.0)
|
|
77
|
-
rspec-support (~> 3.11.0)
|
|
78
|
-
rspec-expectations (3.11.0)
|
|
79
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
|
80
|
-
rspec-support (~> 3.11.0)
|
|
81
|
-
rspec-mocks (3.11.1)
|
|
82
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
|
83
|
-
rspec-support (~> 3.11.0)
|
|
84
|
-
rspec-support (3.11.0)
|
|
85
|
-
rubocop (1.27.0)
|
|
86
|
-
parallel (~> 1.10)
|
|
87
|
-
parser (>= 3.1.0.0)
|
|
88
|
-
rainbow (>= 2.2.2, < 4.0)
|
|
89
|
-
regexp_parser (>= 1.8, < 3.0)
|
|
90
|
-
rexml
|
|
91
|
-
rubocop-ast (>= 1.16.0, < 2.0)
|
|
92
|
-
ruby-progressbar (~> 1.7)
|
|
93
|
-
unicode-display_width (>= 1.4.0, < 3.0)
|
|
94
|
-
rubocop-ast (1.17.0)
|
|
95
|
-
parser (>= 3.1.1.0)
|
|
96
|
-
ruby-progressbar (1.11.0)
|
|
97
|
-
thread_safe (0.3.6)
|
|
98
|
-
tzinfo (1.2.10)
|
|
99
|
-
thread_safe (~> 0.1)
|
|
100
|
-
unicode-display_width (2.1.0)
|
|
101
|
-
|
|
102
|
-
PLATFORMS
|
|
103
|
-
ruby
|
|
104
|
-
|
|
105
|
-
DEPENDENCIES
|
|
106
|
-
activestorage_saas!
|
|
107
|
-
rake (~> 13.0)
|
|
108
|
-
rspec (~> 3.0)
|
|
109
|
-
rubocop (~> 1.21)
|
|
110
|
-
|
|
111
|
-
BUNDLED WITH
|
|
112
|
-
2.3.10
|
data/Rakefile
DELETED
data/activestorage_saas.gemspec
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
activestorage_version = '5.2.5'
|
|
4
|
-
gem_version = 2
|
|
5
|
-
|
|
6
|
-
Gem::Specification.new do |spec|
|
|
7
|
-
spec.name = "activestorage_saas"
|
|
8
|
-
spec.version = "#{activestorage_version}.#{gem_version}"
|
|
9
|
-
spec.authors = ["xiaohui"]
|
|
10
|
-
spec.email = ["xiaohui@tanmer.com"]
|
|
11
|
-
|
|
12
|
-
spec.summary = "Wraps multi-tenant storage services as ActiveStorage service"
|
|
13
|
-
spec.description = "Each tenant can set its own storage service, ActiveStorage service can be dynamically loaded."
|
|
14
|
-
spec.homepage = "https://github.com/xiaohui-zhangxh/activestorage_saas"
|
|
15
|
-
spec.license = "MIT"
|
|
16
|
-
spec.required_ruby_version = ">= 2.6.0"
|
|
17
|
-
|
|
18
|
-
spec.metadata["homepage_uri"] = spec.homepage
|
|
19
|
-
spec.metadata["source_code_uri"] = spec.homepage
|
|
20
|
-
spec.metadata["changelog_uri"] = "#{spec.homepage}/CHANGELOG.md"
|
|
21
|
-
|
|
22
|
-
# Specify which files should be added to the gem when it is released.
|
|
23
|
-
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
24
|
-
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
25
|
-
`git ls-files -z`.split("\x0").reject do |f|
|
|
26
|
-
(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
spec.require_paths = ["lib"]
|
|
31
|
-
|
|
32
|
-
spec.add_dependency "activestorage", activestorage_version
|
|
33
|
-
end
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
class ActiveStorageSaas::DirectUploadsController < ActiveStorage::BaseController
|
|
2
|
-
def create
|
|
3
|
-
blob = ActiveStorage::Blob.create!(blob_args)
|
|
4
|
-
render json: direct_upload_json(blob)
|
|
5
|
-
end
|
|
6
|
-
|
|
7
|
-
def callback
|
|
8
|
-
raise NotImplementedError
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
private
|
|
12
|
-
|
|
13
|
-
def blob_args
|
|
14
|
-
blob_args = params.require(:blob).permit(:filename, :byte_size, :checksum, :content_type).to_h.symbolize_keys
|
|
15
|
-
blob_args.merge! tenant: current_tenant, tenant_storage_service: current_tenant.storage_service
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def direct_upload_json(blob)
|
|
19
|
-
blob.as_json(root: false, methods: :signed_id, only: :signed_id)
|
|
20
|
-
.merge(direct_upload: {
|
|
21
|
-
url: blob.service_url_for_direct_upload,
|
|
22
|
-
method: blob.service_http_method_for_direct_upload,
|
|
23
|
-
responseType: blob.service_http_response_type_for_direct_upload,
|
|
24
|
-
headers: blob.service_headers_for_direct_upload,
|
|
25
|
-
formData: blob.service_form_data_for_direct_upload.presence
|
|
26
|
-
})
|
|
27
|
-
end
|
|
28
|
-
end
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { getMetaValue } from "./helpers"
|
|
2
|
-
|
|
3
|
-
export class BlobRecord {
|
|
4
|
-
constructor(file, checksum, url) {
|
|
5
|
-
this.file = file
|
|
6
|
-
|
|
7
|
-
this.attributes = {
|
|
8
|
-
filename: file.name,
|
|
9
|
-
content_type: file.type || "application/octet-stream",
|
|
10
|
-
byte_size: file.size,
|
|
11
|
-
checksum: checksum
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
this.xhr = new XMLHttpRequest
|
|
15
|
-
this.xhr.open("POST", url, true)
|
|
16
|
-
this.xhr.responseType = "json"
|
|
17
|
-
this.xhr.setRequestHeader("Content-Type", "application/json")
|
|
18
|
-
this.xhr.setRequestHeader("Accept", "application/json")
|
|
19
|
-
this.xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest")
|
|
20
|
-
|
|
21
|
-
const csrfToken = getMetaValue("csrf-token")
|
|
22
|
-
if (csrfToken != undefined) {
|
|
23
|
-
this.xhr.setRequestHeader("X-CSRF-Token", csrfToken)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
this.xhr.addEventListener("load", event => this.requestDidLoad(event))
|
|
27
|
-
this.xhr.addEventListener("error", event => this.requestDidError(event))
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
get status() {
|
|
31
|
-
return this.xhr.status
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
get response() {
|
|
35
|
-
const { responseType, response } = this.xhr
|
|
36
|
-
if (responseType == "json") {
|
|
37
|
-
return response
|
|
38
|
-
} else {
|
|
39
|
-
// Shim for IE 11: https://connect.microsoft.com/IE/feedback/details/794808
|
|
40
|
-
return JSON.parse(response)
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
create(callback) {
|
|
45
|
-
this.callback = callback
|
|
46
|
-
this.xhr.send(JSON.stringify({ blob: this.attributes }))
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
requestDidLoad(event) {
|
|
50
|
-
if (this.status >= 200 && this.status < 300) {
|
|
51
|
-
const { response } = this
|
|
52
|
-
const { direct_upload } = response
|
|
53
|
-
delete response.direct_upload
|
|
54
|
-
this.attributes = response
|
|
55
|
-
this.directUploadData = direct_upload
|
|
56
|
-
this.callback(null, this.toJSON())
|
|
57
|
-
} else {
|
|
58
|
-
this.requestDidError(event)
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
requestDidError(event) {
|
|
63
|
-
this.callback(event, this)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
toJSON() {
|
|
67
|
-
const result = {}
|
|
68
|
-
for (const key in this.attributes) {
|
|
69
|
-
result[key] = this.attributes[key]
|
|
70
|
-
}
|
|
71
|
-
return result
|
|
72
|
-
}
|
|
73
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
export class BlobUpload {
|
|
2
|
-
constructor(blob) {
|
|
3
|
-
this.blob = blob
|
|
4
|
-
this.file = blob.file
|
|
5
|
-
|
|
6
|
-
const { url, headers, method, responseType } = blob.directUploadData
|
|
7
|
-
|
|
8
|
-
this.xhr = new XMLHttpRequest
|
|
9
|
-
this.xhr.open(method || "PUT", url, true)
|
|
10
|
-
this.xhr.responseType = responseType || "text"
|
|
11
|
-
for (const key in headers) {
|
|
12
|
-
this.xhr.setRequestHeader(key, headers[key])
|
|
13
|
-
}
|
|
14
|
-
this.xhr.addEventListener("load", event => this.requestDidLoad(event))
|
|
15
|
-
this.xhr.addEventListener("error", event => this.requestDidError(event))
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
create(callback) {
|
|
19
|
-
this.callback = callback
|
|
20
|
-
if(this.blob.directUploadData.formData){
|
|
21
|
-
var formData
|
|
22
|
-
formData = new FormData()
|
|
23
|
-
for(const key in this.blob.directUploadData.formData){
|
|
24
|
-
formData.append(key, this.blob.directUploadData.formData[key])
|
|
25
|
-
}
|
|
26
|
-
formData.append('file', this.file)
|
|
27
|
-
this.xhr.send(formData)
|
|
28
|
-
}else{
|
|
29
|
-
this.xhr.send(this.file.slice())
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
requestDidLoad(event) {
|
|
34
|
-
const { status, response } = this.xhr
|
|
35
|
-
if (status >= 200 && status < 300) {
|
|
36
|
-
this.callback(null, response)
|
|
37
|
-
} else {
|
|
38
|
-
this.requestDidError(event)
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
requestDidError(event) {
|
|
43
|
-
this.callback(event, this)
|
|
44
|
-
}
|
|
45
|
-
}
|