acts_as_multi_tenant 0.5.1 → 1.0.0.pre.rc1

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
  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