multi-tenant-support 1.1.0 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
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