multi-tenant-support 1.1.0 → 1.3.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d7761ff1721fab8904557ae7af54aca1875d19fb6076bbe5038493c945009eec
4
- data.tar.gz: 43df41f9e15014829828918d4703e77fe6f321bad2f10495e103860abe57cbbf
3
+ metadata.gz: d9a0f7c5067f07151a631c2b67b7b4ab6fb65da04f5b67c8020fec6d89ffe0f6
4
+ data.tar.gz: dbde15d968752339fbc72ec3aed925fa706863c88cdf5f06cb0036fda4c8679c
5
5
  SHA512:
6
- metadata.gz: 7103aec88b69d628baed7e783495cc5e06b8fe49f5751d40aa5e676f2586aa7a0fcfe4d4f6015bfa4409017e533a3fff3a71b945d5426feb2ba5d7ba177f1ede
7
- data.tar.gz: f2e5c63298eee511690622da0d0c47bf0fcdeb80aff543704da2a2a7a047165d5d6eebfda3d44862003329fcc739a3d8278d3ffb7616667087d540c7f9e49006
6
+ metadata.gz: 38e715d1ad5361a4db0cbb2b4b8cde6df8572a72186be05a54949649aad6460e69ef13e2080dbbbe678c64caeb6d7e71e7b9bafc86734266dabe957b947493ca
7
+ data.tar.gz: 3bf0ff4690f643d531b897d487e3ca519df588ea2e08cd7036d3ba65dbbad3e68f129c0c6596b92bf222833112ac59d1ba6eb2c042ac8db8e990fc0267656c67
data/README.md CHANGED
@@ -237,6 +237,12 @@ MultiTenantSupport.under_tenant amazon do
237
237
  end
238
238
  ```
239
239
 
240
+ ### Set current tenant global
241
+
242
+ ```ruby
243
+ MultiTenantSupport::Current.tenant_account = account
244
+ ```
245
+
240
246
  ### Disallow read across tenant by default
241
247
 
242
248
  This gem disallow read across tenant by default. You can check current state through:
@@ -306,6 +312,67 @@ Currently, we don't have a good way to protect this method. So please use `upser
306
312
 
307
313
  This gem has override `unscoped` to prevent the default tenant scope be scoped out. But if you really want to scope out the default tenant scope, you can use `unscope_tenant`.
308
314
 
315
+ ### Console
316
+
317
+ Console does not allow read across tenant by default. But you have several ways to change that:
318
+
319
+ 1. Set `allow_read_across_tenant_by_default` in the initialize file
320
+
321
+ ```ruby
322
+ console do |config|
323
+ config.allow_read_across_tenant_by_default = true
324
+ end
325
+ ```
326
+ 2. Set the environment variable `ALLOW_READ_ACROSS_TENANT` when call consoel command
327
+
328
+ ```bash
329
+ ALLOW_READ_ACROSS_TENANT=1 rails console
330
+ ```
331
+ 3. Manual change it in console
332
+
333
+ ```ruby
334
+ $ rails c
335
+ $ irb(main):001:0> MultiTenantSupport.allow_read_across_tenant
336
+ ```
337
+
338
+ ## Testing
339
+ ### Minitest (Rails default)
340
+
341
+ ```ruby
342
+ # test/test_helper.rb
343
+ require 'multi_tenant_support/minitet'
344
+ ```
345
+ ### RSpec (with Capybara)
346
+
347
+ ```ruby
348
+ # spec/rails_helper.rb or spec/spec_helper.rb
349
+ require 'multi_tenant_support/rspec'
350
+ ```
351
+
352
+ Above code will make sure the `MultiTenantSupport.current_tenant` won't accidentally be reset during integration and system tests. For example:
353
+
354
+ With above testing requre code
355
+
356
+ ```ruby
357
+ # Integration test
358
+ test "a integration test" do
359
+ host! "apple.example.com"
360
+
361
+ assert_no_changes "MultiTenantSupport.current_tenant" do
362
+ get users_path
363
+ end
364
+ end
365
+
366
+ # System test
367
+ test "a system test" do
368
+ Capybara.app_host = "http://apple.example.com"
369
+
370
+ assert_no_changes "MultiTenantSupport.current_tenant" do
371
+ visit users_path
372
+ end
373
+ end
374
+ ```
375
+
309
376
  ## Code Example
310
377
 
311
378
  ### Database Schema
@@ -340,6 +407,10 @@ MultiTenantSupport.configure do
340
407
  config.excluded_subdomains = ['www']
341
408
  config.host = 'example.com'
342
409
  end
410
+
411
+ console do |config|
412
+ config.allow_read_across_tenant_by_default = false
413
+ end
343
414
  end
344
415
  ```
345
416
 
@@ -12,6 +12,10 @@ MultiTenantSupport.configure do
12
12
  config.excluded_subdomains = ['www']
13
13
  config.host = 'REPLACE.ME'
14
14
  end
15
+
16
+ console do |config|
17
+ config.allow_read_across_tenant_by_default = false
18
+ end
15
19
  end
16
20
 
17
21
  # Uncomment if you are using sidekiq without ActiveJob
@@ -4,6 +4,7 @@ require "multi_tenant_support/errors"
4
4
  require "multi_tenant_support/config/app"
5
5
  require "multi_tenant_support/config/controller"
6
6
  require "multi_tenant_support/config/model"
7
+ require "multi_tenant_support/config/console"
7
8
  require "multi_tenant_support/current"
8
9
  require "multi_tenant_support/find_tenant_account"
9
10
  require "multi_tenant_support/concern/controller_concern"
@@ -33,6 +34,10 @@ module MultiTenantSupport
33
34
  end
34
35
  end
35
36
 
37
+ def allow_read_across_tenant?
38
+ !disallow_read_across_tenant?
39
+ end
40
+
36
41
  def disallow_read_across_tenant?
37
42
  !Current.allow_read_across_tenant
38
43
  end
@@ -1,4 +1,5 @@
1
1
  module MultiTenantSupport
2
+
2
3
  module ActiveJob
3
4
  extend ActiveSupport::Concern
4
5
 
@@ -6,6 +7,40 @@ module MultiTenantSupport
6
7
  attr_accessor :current_tenant
7
8
  end
8
9
 
10
+ class_methods do
11
+
12
+ if Gem::Version.new(Rails.version) < Gem::Version.new("7.0.0.alpha1")
13
+ def perform_now(*args)
14
+ job = job_or_instantiate(*args)
15
+ job.current_tenant = MultiTenantSupport.current_tenant
16
+ job.perform_now
17
+ end
18
+ else
19
+ eval("
20
+ def perform_now(...)
21
+ job = job_or_instantiate(...)
22
+ job.current_tenant = MultiTenantSupport.current_tenant
23
+ job.perform_now
24
+ end
25
+ ")
26
+ end
27
+
28
+ def execute(job_data)
29
+ keep_current_tenant_unchange do
30
+ super(job_data)
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def keep_current_tenant_unchange
37
+ _current_tenant = MultiTenantSupport::Current.tenant_account
38
+ yield
39
+ ensure
40
+ MultiTenantSupport::Current.tenant_account = _current_tenant
41
+ end
42
+ end
43
+
9
44
  def perform_now
10
45
  MultiTenantSupport.under_tenant(current_tenant) do
11
46
  super
@@ -43,6 +78,25 @@ module MultiTenantSupport
43
78
  tenant_klass.find tenant_id
44
79
  end
45
80
  end
81
+
82
+ module ConfiguredJob
83
+ if Gem::Version.new(Rails.version) < Gem::Version.new("7.0.0.alpha1")
84
+ def perform_now(*args)
85
+ job = @job_class.new(*args)
86
+ job.current_tenant = MultiTenantSupport.current_tenant
87
+ job.perform_now
88
+ end
89
+ else
90
+ eval("
91
+ def perform_now(...)
92
+ job = @job_class.new(...)
93
+ job.current_tenant = MultiTenantSupport.current_tenant
94
+ job.perform_now
95
+ end
96
+ ")
97
+ end
98
+ end
46
99
  end
47
100
 
48
- ActiveJob::Base.include(MultiTenantSupport::ActiveJob)
101
+ ActiveJob::Base.include(MultiTenantSupport::ActiveJob)
102
+ ActiveJob::ConfiguredJob.prepend(MultiTenantSupport::ConfiguredJob)
@@ -10,10 +10,6 @@ module MultiTenantSupport
10
10
 
11
11
  private
12
12
 
13
- define_method(MultiTenantSupport.current_tenant_account_method) do
14
- instance_variable_get("@#{MultiTenantSupport.current_tenant_account_method}")
15
- end
16
-
17
13
  def set_current_tenant_account
18
14
  tenant_account = find_current_tenant_account
19
15
  MultiTenantSupport::Current.tenant_account = tenant_account
@@ -31,8 +27,12 @@ module MultiTenantSupport
31
27
  end
32
28
 
33
29
  module ViewHelper
34
- define_method(MultiTenantSupport.current_tenant_account_method) do
35
- instance_variable_get("@#{MultiTenantSupport.current_tenant_account_method}")
30
+ extend ActiveSupport::Concern
31
+
32
+ included do
33
+ define_method(MultiTenantSupport.current_tenant_account_method) do
34
+ instance_variable_get("@#{MultiTenantSupport.current_tenant_account_method}")
35
+ end
36
36
  end
37
37
  end
38
38
  end
@@ -0,0 +1,21 @@
1
+ module MultiTenantSupport
2
+
3
+ module Config
4
+ class Console
5
+ attr_writer :allow_read_across_tenant_by_default
6
+
7
+ def allow_read_across_tenant_by_default
8
+ @allow_read_across_tenant_by_default ||= false
9
+ end
10
+ end
11
+ end
12
+
13
+ module_function
14
+ def console
15
+ @console ||= Config::Console.new
16
+ return @console unless block_given?
17
+
18
+ yield @console
19
+ end
20
+
21
+ end
@@ -0,0 +1,7 @@
1
+ require_relative "./test/integration"
2
+ require_relative "./test/system"
3
+ require_relative "./test/capybara"
4
+
5
+ ActionDispatch::IntegrationTest.prepend(MultiTenantSupport::Test::Integration)
6
+ ActionDispatch::SystemTestCase.prepend(MultiTenantSupport::Test::System)
7
+ Capybara::Node::Element.prepend(MultiTenantSupport::Test::Capybara)
@@ -9,5 +9,13 @@ module MultiTenantSupport
9
9
  config.app_generators.templates.unshift(active_record_templates)
10
10
  end
11
11
 
12
+ console do
13
+ if ENV["ALLOW_READ_ACROSS_TENANT"] || MultiTenantSupport.console.allow_read_across_tenant_by_default
14
+ MultiTenantSupport.allow_read_across_tenant
15
+ else
16
+ MultiTenantSupport.disallow_read_across_tenant
17
+ end
18
+ end
19
+
12
20
  end
13
21
  end
@@ -0,0 +1,13 @@
1
+ require_relative "./test/integration"
2
+ require_relative "./test/system"
3
+ require_relative "./test/capybara"
4
+
5
+ RSpec.configure do |config|
6
+ config.include MultiTenantSupport::Test::Integration, type: :request
7
+ config.include MultiTenantSupport::Test::Integration, type: :controller
8
+
9
+ config.include MultiTenantSupport::Test::System, type: :system
10
+ config.include MultiTenantSupport::Test::System, type: :feature
11
+ end
12
+
13
+ Capybara::Node::Element.prepend(MultiTenantSupport::Test::Capybara)
@@ -0,0 +1,57 @@
1
+ module MultiTenantSupport
2
+ module Test
3
+ module Capybara
4
+
5
+ def set(value, **options)
6
+ keep_context_tenant_unchange do
7
+ super(value, **options)
8
+ end
9
+ end
10
+
11
+ def select_option(wait: nil)
12
+ keep_context_tenant_unchange do
13
+ super(wait: wait)
14
+ end
15
+ end
16
+
17
+ def unselect_option(wait: nil)
18
+ keep_context_tenant_unchange do
19
+ super(wait: wait)
20
+ end
21
+ end
22
+
23
+ def perform_click_action(keys, wait: nil, **options)
24
+ keep_context_tenant_unchange do
25
+ super
26
+ end
27
+ end
28
+
29
+ def trigger(event)
30
+ keep_context_tenant_unchange do
31
+ super
32
+ end
33
+ end
34
+
35
+ def evaluate_script(script, *args)
36
+ keep_context_tenant_unchange do
37
+ super
38
+ end
39
+ end
40
+
41
+ def evaluate_async_script(script, *args)
42
+ keep_context_tenant_unchange do
43
+ super
44
+ end
45
+ end
46
+
47
+ def keep_context_tenant_unchange
48
+ _current_tenant = MultiTenantSupport::Current.tenant_account
49
+ MultiTenantSupport::Current.tenant_account = nil # Simulate real circumstance
50
+ yield
51
+ ensure
52
+ MultiTenantSupport::Current.tenant_account = _current_tenant
53
+ end
54
+
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,29 @@
1
+ module MultiTenantSupport
2
+ module Test
3
+ module Integration
4
+
5
+ %i[get post patch put delete head options].each do |method|
6
+ define_method method do |path, **args|
7
+ keep_context_tenant_unchange do
8
+ super(path, **args)
9
+ end
10
+ end
11
+ end
12
+
13
+ def follow_redirect(**args)
14
+ keep_context_tenant_unchange do
15
+ super(**args)
16
+ end
17
+ end
18
+
19
+ def keep_context_tenant_unchange
20
+ _current_tenant = MultiTenantSupport::Current.tenant_account
21
+ MultiTenantSupport::Current.tenant_account = nil # Simulate real circumstance
22
+ yield
23
+ ensure
24
+ MultiTenantSupport::Current.tenant_account = _current_tenant
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,38 @@
1
+ module MultiTenantSupport
2
+ module Test
3
+ module System
4
+
5
+ %i[
6
+ visit refresh click_on go_back go_forward
7
+ check choose click_button click_link
8
+ fill_in uncheck check unselect select
9
+ execute_script evaluate_script
10
+ ].each do |method|
11
+ if RUBY_VERSION >= '2.7'
12
+ class_eval <<~METHOD, __FILE__, __LINE__ + 1
13
+ def #{method}(...)
14
+ keep_context_tenant_unchange do
15
+ super(...)
16
+ end
17
+ end
18
+ METHOD
19
+ else
20
+ define_method method do |*args, &block|
21
+ keep_context_tenant_unchange do
22
+ super(*args, &block)
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ def keep_context_tenant_unchange
29
+ _current_tenant = MultiTenantSupport::Current.tenant_account
30
+ MultiTenantSupport::Current.tenant_account = nil # Simulate real circumstance
31
+ yield
32
+ ensure
33
+ MultiTenantSupport::Current.tenant_account = _current_tenant
34
+ end
35
+
36
+ end
37
+ end
38
+ end
@@ -1,3 +1,3 @@
1
1
  module MultiTenantSupport
2
- VERSION = '1.1.0'
2
+ VERSION = '1.3.1'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: multi-tenant-support
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hopper Gee
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-06 00:00:00.000000000 Z
11
+ date: 2021-10-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -45,13 +45,19 @@ files:
45
45
  - lib/multi_tenant_support/concern/controller_concern.rb
46
46
  - lib/multi_tenant_support/concern/model_concern.rb
47
47
  - lib/multi_tenant_support/config/app.rb
48
+ - lib/multi_tenant_support/config/console.rb
48
49
  - lib/multi_tenant_support/config/controller.rb
49
50
  - lib/multi_tenant_support/config/model.rb
50
51
  - lib/multi_tenant_support/current.rb
51
52
  - lib/multi_tenant_support/errors.rb
52
53
  - lib/multi_tenant_support/find_tenant_account.rb
54
+ - lib/multi_tenant_support/minitest.rb
53
55
  - lib/multi_tenant_support/railtie.rb
56
+ - lib/multi_tenant_support/rspec.rb
54
57
  - lib/multi_tenant_support/sidekiq.rb
58
+ - lib/multi_tenant_support/test/capybara.rb
59
+ - lib/multi_tenant_support/test/integration.rb
60
+ - lib/multi_tenant_support/test/system.rb
55
61
  - lib/multi_tenant_support/version.rb
56
62
  - lib/tasks/multi_tenant_support_tasks.rake
57
63
  homepage: https://github.com/hoppergee/multi-tenant-support