acts_as_multi_tenant 0.5.1 → 1.0.0.pre.rc1

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
  SHA1:
3
- metadata.gz: 900858457990afa4c3972a78b8fadc624c22134d
4
- data.tar.gz: 0a0fc2e1ac224944d60563be966d9818421a4789
3
+ metadata.gz: de0c6576d3305ddd5a2bc8b939351675e799e755
4
+ data.tar.gz: d6ccc7ffbe9f7251f46dffe2618879d265c173e4
5
5
  SHA512:
6
- metadata.gz: b43d5b7c8e5eef9226b7c3f3ba7ea3618ee9d473de7dae3c59bcd4ae16be4225a1e5ff1cb29fdddb9c50fa54fdb7c05a275927a577837f0ac4d976a00a5673b0
7
- data.tar.gz: 5072aac61f705c4a66d52579bce2efee8cc772f303177a617eaa97afe72c0334109def5469fd1b8d05746e99449ce5f7f8ae3280c0bdc58d0c69382604db4b4f
6
+ metadata.gz: d71a6bb84ed043f4b8f4314cdd7d54f9c1389643bd34300699946f4d89d2052204689dfb7a3f901a4a7a5be0e9c0e76efa66bea2a3b59218a493e55e2d61b517
7
+ data.tar.gz: b6869cef3c3c3023f41771c400bd387f79535696eea3bd7242029e1f74e66048500e6cd7f7638d3003e53c619f8475a5374e00ae8398cff0aa5cde9d26615613
data/README.md CHANGED
@@ -21,19 +21,19 @@ use MultiTenant::Middleware,
21
21
  # (required) Fetch the identifier of the current tenant from a Rack::Request object
22
22
  identifier: ->(req) { req.host.split(/\./)[0] },
23
23
 
24
- # (optional) Array of tentants that don't exist in the database, but should be allowed through anyway.
25
- # IMPORTANT For these, Tenant.current will be nil!
26
- global_identifiers: %w(global),
27
-
28
- # (optional) Array of Strings or Regexps for paths that don't require a tenant. Only applies
29
- # when the tenant isn't specified in the request - not when a given tenant can't be found.
30
- global_paths: [
31
- '/about',
32
- %r{^/api/v\d+/login$},
33
- ],
34
-
35
- # (optional) Returns a Rack response when a tenant couldn't be found in the db, or when
36
- # a tenant isn't given (and isn't in the `global_paths` list)
24
+ # (optional) A Hash of fake identifiers that should be allowed through. Each identifier will have a
25
+ # Hash of Regex paths with Symbol http methods (or arrays thereof), or :any. These path & method combos
26
+ # will be allowed through when the identifier matches. All others will be blocked.
27
+ # IMPORTANT Tenant.current will be nil!
28
+ globals: {
29
+ "global" => {
30
+ %r{\A/api/widgets/} => :any,
31
+ %r{\A/api/splines/} => [:get, :post]
32
+ }
33
+ },
34
+
35
+ # (optional) Returns a Rack response when a tenant couldn't be found in the db (excluding globals),
36
+ # or when a tenant isn't given.
37
37
  not_found: ->(x) {
38
38
  body = {errors: ["'%s' is not a valid tenant!" % x]}.to_json
39
39
  [400, {'Content-Type' => 'application/json', 'Content-Length' => body.size.to_s}, [body]]
@@ -13,16 +13,16 @@ module MultiTenant
13
13
  # # A Proc that returns the tenant identifier that's used to look up the tenant. (i.e. :using option passed to acts_as_tenant)
14
14
  # identifier: ->(req) { req.host.split(/\./)[0] },
15
15
  #
16
- # # (optional) Array of tentants that don't exist in the database, but should be allowed through anyway.
17
- # # IMPORTANT For these, Tenant.current will be nil!
18
- # global_identifiers: %w(global),
19
- #
20
- # # (optional) Array of Strings or Regexps for paths that don't require a tenant. Only applies
21
- # # when the tenant isn't specified in the request - not when a given tenant can't be found.
22
- # global_paths: [
23
- # '/about',
24
- # %r{^/api/v\d+/login$},
25
- # ],
16
+ # # (optional) A Hash of fake identifiers that should be allowed through. Each identifier will have a
17
+ # # Hash of Regex paths with Symbol http methods (or arrays thereof), or :any. These path & method combos
18
+ # # will be allowed through when the identifier matches. All others will be blocked.
19
+ # # IMPORTANT Tenant.current will be nil!
20
+ # globals: {
21
+ # "global" => {
22
+ # %r{\A/api/widgets/} => :any,
23
+ # %r{\A/api/splines/} => [:get, :post]
24
+ # }
25
+ # },
26
26
  #
27
27
  # # (optional) Returns a Rack response when a tenant couldn't be found in the db, or when
28
28
  # # a tenant isn't given (and isn't in the `global_paths` list)
@@ -38,14 +38,8 @@ module MultiTenant
38
38
  # @return [Proc] A Proc which accepts a Rack::Request and returns some identifier for tenant lookup
39
39
  attr_accessor :identifier
40
40
 
41
- # @return [Set<String>] array of "fake" identifiers that will be allowed through, but without setting a current tentant
42
- attr_accessor :global_identifiers
43
-
44
- # @return [Set<String>] An array of path strings that don't requite a tenant to be given
45
- attr_accessor :global_strings
46
-
47
- # @return [Set<String>] An array of path regexes that don't requite a tenant to be given
48
- attr_accessor :global_regexes
41
+ # @return [Hash] Global identifiers and their allowed paths and methods
42
+ attr_accessor :globals
49
43
 
50
44
  # @return [Proc] A Proc which accepts a (non-existent or blank) tenant identifier and returns a rack response describing
51
45
  # the error. Defaults to a 404 and some shitty html.
@@ -60,39 +54,36 @@ module MultiTenant
60
54
  # Initialize a new multi tenant Rack middleware.
61
55
  #
62
56
  # @param app the Rack app
63
- # @param opts [Hash] Required: :model, :identifier. Optional: :global_identifiers, :global_paths, :not_found.
57
+ # @param opts [Hash] Required: :model, :identifier. Optional: :globals, :not_found.
64
58
  #
65
59
  def initialize(app, opts)
66
60
  @app = app
67
61
  self.model = opts.fetch :model
68
62
  self.identifier = opts.fetch :identifier
69
- self.global_identifiers = Set.new(Array(opts[:global_identifiers]))
70
- self.global_strings = Set.new(Array(opts[:global_paths]).select { |x| x.is_a? String })
71
- self.global_regexes = Array(opts[:global_paths]).select { |x| x.is_a? Regexp }
63
+ self.globals = (opts[:globals] || {}).reduce({}) { |a, (global, patterns)|
64
+ a[global] = patterns.reduce({}) { |aa, (path, methods)|
65
+ aa[path] = methods == :any ? :any : Set.new(Array(methods).map { |m| m.to_s.upcase })
66
+ aa
67
+ }
68
+ a
69
+ }
72
70
  self.not_found = opts[:not_found] || DEFAULT_NOT_FOUND
73
71
  end
74
72
 
75
73
  # Rack request call
76
74
  def call(env)
75
+ tenant_class.current = nil
77
76
  request = Rack::Request.new env
78
77
  tenant_identifier = identifier.(request)
79
78
 
80
- if tenant_identifier.blank?
81
- if global_strings.include? request.path or global_regexes.any? { |x| x =~ request.path }
82
- tenant_class.current = nil
83
- return @app.call env
84
- else
85
- return not_found.(tenant_identifier)
86
- end
87
- end
79
+ if (allowed_paths = globals[tenant_identifier])
80
+ allowed = path_matches?(request, allowed_paths)
81
+ return allowed ? @app.call(env) : not_found.(tenant_identifier)
88
82
 
89
- tenant_record = tenant_identifier.present? ? tenant_class.where({tenant_class.tenant_identifier => tenant_identifier}).first : nil
90
- if tenant_record
91
- tenant_class.current = tenant_record
92
- return @app.call env
93
- elsif global_identifiers.include? tenant_identifier
94
- tenant_class.current = nil
83
+ elsif (tenant = tenant_class.where({tenant_class.tenant_identifier => tenant_identifier}).first)
84
+ tenant_class.current = tenant
95
85
  return @app.call env
86
+
96
87
  else
97
88
  return not_found.(tenant_identifier)
98
89
  end
@@ -100,6 +91,12 @@ module MultiTenant
100
91
  tenant_class.current = nil
101
92
  end
102
93
 
94
+ def path_matches?(req, paths)
95
+ paths.any? { |(path, methods)|
96
+ (path == req.path || path =~ req.path) && (methods == :any || methods.include?(req.request_method))
97
+ }
98
+ end
99
+
103
100
  # Infers and returns the tenant model class this middleware is handling
104
101
  def tenant_class
105
102
  @tenant_class ||= if self.model.respond_to?(:call)
@@ -1,4 +1,4 @@
1
1
  module MultiTenant
2
2
  # Gem version
3
- VERSION = '0.5.1'.freeze
3
+ VERSION = '1.0.0.pre.rc1'.freeze
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts_as_multi_tenant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 1.0.0.pre.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jordan Hollinger
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2017-09-11 00:00:00.000000000 Z
13
+ date: 2018-02-16 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
@@ -76,12 +76,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
76
76
  version: 2.1.0
77
77
  required_rubygems_version: !ruby/object:Gem::Requirement
78
78
  requirements:
79
- - - ">="
79
+ - - ">"
80
80
  - !ruby/object:Gem::Version
81
- version: '0'
81
+ version: 1.3.1
82
82
  requirements: []
83
83
  rubyforge_project:
84
- rubygems_version: 2.5.2
84
+ rubygems_version: 2.5.2.1
85
85
  signing_key:
86
86
  specification_version: 4
87
87
  summary: An ActiveRecord plugin for multi-tenant databases