rabarber 1.1.0 → 1.2.0

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: bf7a31c94f695cb0edb8209562d07971f3fc712bd868bf589fd4b1ee4ffb2865
4
- data.tar.gz: 2c5d939673b685beba64910dc4ee361f811d760cc8bb6982b502b3e0f4354c5b
3
+ metadata.gz: e7eaa4eaef0f5c6d072e3a5b545b0ce152651df15b521be933aac78e1add85ba
4
+ data.tar.gz: d0557fcd900f2bebd58f6489c2f3f79c2f95c7c14bbeeeb59a294fdfcbcb3f49
5
5
  SHA512:
6
- metadata.gz: c513a7ea4140a12b37384b0bc91969eec5305f1d422a24d3a6117607d9b1b0dbdaa77398f4ce49fa2025b9fb1101439c09c274cded09acbb58a46b0bd54b9b3b
7
- data.tar.gz: 93f18fe608254896b97e772e05d9c94e31f17f769fd4d4f5314460450d19408c7f3f41a1197a7834b43ab81e6bbf694446ed94b23df9af6b9e904040534afc1a
6
+ metadata.gz: cadc08751bf39ab0c6eb8a357854fe00bb478533a7f5a7e0760929d6acedad0fcecb31e17c21c980c764d59302a569df74e847f09c778b2e3f1c257c520c4336
7
+ data.tar.gz: 7067e81820ce07c0929e3f18ad079c9cfa44b0dc473138b042e4e882b8db1cda17bbc680a431634c42695434a088605fd897ab4a2e25a4d4d2b9bac7c8180fd5
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## 1.2.0
2
+
3
+ - Enhance handling of missing actions and roles specified in `grant_access` method by raising an error for missing actions and logging a warning for missing roles.
4
+ - Introduce `when_actions_missing` and `when_roles_missing` configuration options, allowing to customize the behavior when actions or roles are not found.
5
+
1
6
  ## 1.1.0
2
7
 
3
8
  - Add support for `unless` argument in `grant_access` method, allowing to define negated dynamic rules
data/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [![Gem Version](https://badge.fury.io/rb/rabarber.svg)](http://badge.fury.io/rb/rabarber)
4
4
  [![Github Actions badge](https://github.com/enjaku4/rabarber/actions/workflows/ci.yml/badge.svg)](https://github.com/enjaku4/rabarber/actions/workflows/ci.yml)
5
5
 
6
- Rabarber is an authorization library for Ruby on Rails, primarily designed for use in the application layer but not limited to that. It offers a set of useful tools for managing user roles and defining authorization rules.
6
+ Rabarber is a role-based authorization library for Ruby on Rails, primarily designed for use in the application layer but not limited to that. It offers a set of useful tools for managing user roles and defining authorization rules.
7
7
 
8
8
  ---
9
9
 
@@ -63,20 +63,26 @@ rails db:migrate
63
63
 
64
64
  ## Configuration
65
65
 
66
- Rabarber can be configured by adding the following code into an initializer:
66
+ Rabarber can be configured by using `.configure` method in an initializer:
67
67
 
68
68
  ```rb
69
69
  Rabarber.configure do |config|
70
70
  config.current_user_method = :authenticated_user
71
71
  config.must_have_roles = true
72
- config.when_unauthorized = ->(controller) {
73
- controller.head 418
74
- }
72
+ config.when_actions_missing = -> (missing_actions, context) { ... }
73
+ config.when_roles_missing = -> (missing_roles, context) { ... }
74
+ config.when_unauthorized = -> (controller) { ... }
75
75
  end
76
76
  ```
77
77
  - `current_user_method` must be a symbol representing the method that returns the currently authenticated user. The default value is `:current_user`.
78
+
78
79
  - `must_have_roles` must be a boolean determining whether a user with no roles can access endpoints permitted to everyone. The default value is `false` (allowing users without roles to access endpoints permitted to everyone).
79
- - `when_unauthorized` must be a lambda where you can define your actions when access is not authorized (`controller` is an instance of the controller where the code is executed). By default, the user is redirected back if the request format is HTML; otherwise, a 401 Unauthorized response is sent.
80
+
81
+ - `when_actions_missing` must be a proc where you can define the behaviour when the actions specified in `grant_access` method cannot be found in the controller (`missing_actions` is an array of missing actions, `context` is a hash that looks like this: `{ controller: "InvoicesController" }`). This check is performed on every request and when the application is initialized if `eager_load` configuration is enabled in Rails. By default, an error is raised when actions are missing.
82
+
83
+ - `when_roles_missing` must be a proc where you can define the behaviour when the roles specified in `grant_access` method cannot be found in the database (`missing_roles` is an array of missing roles, `context` is a hash that looks like this: `{ controller: "InvoicesController", action: "index" }`). This check is performed on every request and when the application is initialized if `eager_load` configuration is enabled in Rails. By default, only a warning is logged when roles are missing.
84
+
85
+ - `when_unauthorized` must be a proc where you can define the behaviour when access is not authorized (`controller` is an instance of the controller where the code is executed). By default, the user is redirected back if the request format is HTML; otherwise, a 401 Unauthorized response is sent.
80
86
 
81
87
  ## Roles
82
88
 
@@ -108,7 +114,7 @@ You can also explicitly create new roles simply by using:
108
114
  ```rb
109
115
  Rabarber::Role.create(name: "manager")
110
116
  ```
111
- The role names are unique.
117
+ The role names must be unique.
112
118
 
113
119
  **`#revoke_roles`**
114
120
 
@@ -145,12 +151,6 @@ Rabarber::Role.names
145
151
 
146
152
  `Rabarber::Role` is a model that represents roles within your application. It has a single attribute, `name`, which is validated for both uniqueness and presence. You can treat `Rabarber::Role` as a regular Rails model and use Active Record methods on it if necessary.
147
153
 
148
- *Utilize the aforementioned methods to manipulate user roles. For example, create a UI for managing roles or assign roles during migration or runtime (e.g. when the user is created).*
149
-
150
- *You are also encouraged to write your own authorization policies based on `#has_role?` method (e.g. to scope the data that the role can access).*
151
-
152
- *Adapt the tools Rabarber provides to fit the requirements of your application.*
153
-
154
154
  ## Authorization Rules
155
155
 
156
156
  Include `Rabarber::Authorization` module into the controller that needs authorization rules to be applied (authorization rules will be applied to the controller and its children). Typically, it is `ApplicationController`, but it can be any controller.
@@ -256,7 +256,7 @@ class InvoicesController < ApplicationController
256
256
  end
257
257
  end
258
258
  ```
259
- You can pass a dynamic rule as `if` or `unless` argument. It can be a symbol (the method with the same name will be called) or a lambda.
259
+ You can pass a dynamic rule as `if` or `unless` argument. It can be a symbol (the method with the same name will be called) or a proc.
260
260
 
261
261
  Rules defined in child classes don't override parent rules but rather add to them:
262
262
  ```rb
@@ -12,6 +12,6 @@ class CreateRabarberRoles < ActiveRecord::Migration[<%= ActiveRecord::Migration.
12
12
  t.belongs_to :roleable, null: false, index: true, foreign_key: { to_table: raise(Rabarber::Error, "Please specify your user model's table name") }
13
13
  end
14
14
 
15
- add_index :rabarber_roles_roleables, %i[role_id roleable_id], unique: true
15
+ add_index :rabarber_roles_roleables, [:role_id, :roleable_id], unique: true
16
16
  end
17
17
  end
@@ -6,38 +6,78 @@ module Rabarber
6
6
  class Configuration
7
7
  include Singleton
8
8
 
9
- attr_reader :current_user_method, :must_have_roles, :when_unauthorized
9
+ attr_reader :current_user_method, :must_have_roles, :when_actions_missing, :when_roles_missing, :when_unauthorized
10
10
 
11
11
  def initialize
12
- @current_user_method = :current_user
13
- @must_have_roles = false
14
- @when_unauthorized = ->(controller) do
15
- if controller.request.format.html?
16
- controller.redirect_back fallback_location: controller.main_app.root_path
17
- else
18
- controller.head(:unauthorized)
19
- end
20
- end
12
+ @current_user_method = default_current_user_method
13
+ @must_have_roles = default_must_have_roles
14
+ @when_actions_missing = default_when_actions_missing
15
+ @when_roles_missing = default_when_roles_missing
16
+ @when_unauthorized = default_when_unauthorized
21
17
  end
22
18
 
23
19
  def current_user_method=(method_name)
24
- unless (method_name.is_a?(Symbol) || method_name.is_a?(String)) && method_name.present?
25
- raise ConfigurationError, "Configuration 'current_user_method' must be a Symbol or a String"
26
- end
27
-
28
- @current_user_method = method_name.to_sym
20
+ @current_user_method = Rabarber::Input::Types::Symbols.new(
21
+ method_name, Rabarber::ConfigurationError, "Configuration 'current_user_method' must be a Symbol or a String"
22
+ ).process
29
23
  end
30
24
 
31
25
  def must_have_roles=(value)
32
- raise ConfigurationError, "Configuration 'must_have_roles' must be a Boolean" unless [true, false].include?(value)
26
+ @must_have_roles = Rabarber::Input::Types::Booleans.new(
27
+ value, Rabarber::ConfigurationError, "Configuration 'must_have_roles' must be a Boolean"
28
+ ).process
29
+ end
30
+
31
+ def when_actions_missing=(callable)
32
+ @when_actions_missing = Rabarber::Input::Types::Procs.new(
33
+ callable, Rabarber::ConfigurationError, "Configuration 'when_actions_missing' must be a Proc"
34
+ ).process
35
+ end
33
36
 
34
- @must_have_roles = value
37
+ def when_roles_missing=(callable)
38
+ @when_roles_missing = Rabarber::Input::Types::Procs.new(
39
+ callable, Rabarber::ConfigurationError, "Configuration 'when_roles_missing' must be a Proc"
40
+ ).process
35
41
  end
36
42
 
37
43
  def when_unauthorized=(callable)
38
- raise ConfigurationError, "Configuration 'when_unauthorized' must be a Proc" unless callable.is_a?(Proc)
44
+ @when_unauthorized = Rabarber::Input::Types::Procs.new(
45
+ callable, Rabarber::ConfigurationError, "Configuration 'when_unauthorized' must be a Proc"
46
+ ).process
47
+ end
48
+
49
+ private
39
50
 
40
- @when_unauthorized = callable
51
+ def default_current_user_method
52
+ :current_user
53
+ end
54
+
55
+ def default_must_have_roles
56
+ false
57
+ end
58
+
59
+ def default_when_actions_missing
60
+ -> (missing_actions, context) {
61
+ raise Rabarber::Error, "Missing actions: #{missing_actions}, context: #{context[:controller]}"
62
+ }
63
+ end
64
+
65
+ def default_when_roles_missing
66
+ -> (missing_roles, context) {
67
+ delimiter = context[:action] ? "#" : ""
68
+ message = "Missing roles: #{missing_roles}, context: #{context[:controller]}#{delimiter}#{context[:action]}"
69
+ Rails.logger.tagged("Rabarber") { Rails.logger.warn message }
70
+ }
71
+ end
72
+
73
+ def default_when_unauthorized
74
+ -> (controller) do
75
+ if controller.request.format.html?
76
+ controller.redirect_back fallback_location: controller.main_app.root_path
77
+ else
78
+ controller.head(:unauthorized)
79
+ end
80
+ end
41
81
  end
42
82
  end
43
83
  end
@@ -12,18 +12,27 @@ module Rabarber
12
12
  def grant_access(action: nil, roles: nil, if: nil, unless: nil)
13
13
  dynamic_rule, negated_dynamic_rule = binding.local_variable_get(:if), binding.local_variable_get(:unless)
14
14
 
15
- Permissions.write(self, action, roles, dynamic_rule, negated_dynamic_rule)
15
+ Rabarber::Permissions.add(
16
+ self,
17
+ Rabarber::Input::Actions.new(action).process,
18
+ Rabarber::Input::Roles.new(roles).process,
19
+ Rabarber::Input::DynamicRules.new(dynamic_rule).process,
20
+ Rabarber::Input::DynamicRules.new(negated_dynamic_rule).process
21
+ )
16
22
  end
17
23
  end
18
24
 
19
25
  private
20
26
 
21
27
  def verify_access
22
- return if Permissions.access_granted?(
23
- send(::Rabarber::Configuration.instance.current_user_method).roles, self.class, action_name.to_sym, self
28
+ Rabarber::Missing::Actions.new(self.class).handle
29
+ Rabarber::Missing::Roles.new(self.class).handle
30
+
31
+ return if Rabarber::Permissions.access_granted?(
32
+ send(Rabarber::Configuration.instance.current_user_method).roles, self.class, action_name.to_sym, self
24
33
  )
25
34
 
26
- ::Rabarber::Configuration.instance.when_unauthorized.call(self)
35
+ Rabarber::Configuration.instance.when_unauthorized.call(self)
27
36
  end
28
37
  end
29
38
  end
@@ -3,13 +3,13 @@
3
3
  module Rabarber
4
4
  module Helpers
5
5
  def visible_to(*roles, &block)
6
- return unless send(::Rabarber::Configuration.instance.current_user_method).has_role?(*roles)
6
+ return unless send(Rabarber::Configuration.instance.current_user_method).has_role?(*roles)
7
7
 
8
8
  capture(&block)
9
9
  end
10
10
 
11
11
  def hidden_from(*roles, &block)
12
- return if send(::Rabarber::Configuration.instance.current_user_method).has_role?(*roles)
12
+ return if send(Rabarber::Configuration.instance.current_user_method).has_role?(*roles)
13
13
 
14
14
  capture(&block)
15
15
  end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rabarber
4
+ module Input
5
+ class Actions < Rabarber::Input::Base
6
+ def initialize(
7
+ value,
8
+ error_type = Rabarber::InvalidArgumentError,
9
+ error_message = "Action name must be a Symbol or a String"
10
+ )
11
+ super
12
+ end
13
+
14
+ private
15
+
16
+ def valid?
17
+ (value.is_a?(String) || value.is_a?(Symbol)) && value.present? || value.nil?
18
+ end
19
+
20
+ def processed_value
21
+ case value
22
+ when String, Symbol
23
+ value.to_sym
24
+ when nil
25
+ value
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rabarber
4
+ module Input
5
+ class Base
6
+ attr_reader :value, :error_type, :error_message
7
+
8
+ def initialize(value, error_type, error_message)
9
+ @value = value
10
+ @error_type = error_type
11
+ @error_message = error_message
12
+ end
13
+
14
+ def process
15
+ valid? ? processed_value : raise_error
16
+ end
17
+
18
+ private
19
+
20
+ def valid?
21
+ raise NotImplementedError
22
+ end
23
+
24
+ def processed_value
25
+ raise NotImplementedError
26
+ end
27
+
28
+ def raise_error
29
+ raise error_type, error_message
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rabarber
4
+ module Input
5
+ class DynamicRules < Rabarber::Input::Base
6
+ def initialize(
7
+ value,
8
+ error_type = Rabarber::InvalidArgumentError,
9
+ error_message = "Dynamic rule must be a Symbol, a String, or a Proc"
10
+ )
11
+ super
12
+ end
13
+
14
+ private
15
+
16
+ def valid?
17
+ (value.is_a?(String) || value.is_a?(Symbol)) && value.present? || value.nil? || value.is_a?(Proc)
18
+ end
19
+
20
+ def processed_value
21
+ case value
22
+ when String, Symbol
23
+ value.to_sym
24
+ when Proc, nil
25
+ value
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rabarber
4
+ module Input
5
+ class Roles < Rabarber::Input::Base
6
+ REGEX = /\A[a-z0-9_]+\z/
7
+
8
+ def initialize(
9
+ value,
10
+ error_type = Rabarber::InvalidArgumentError,
11
+ error_message =
12
+ "Role names must be Symbols or Strings and may only contain lowercase letters, numbers and underscores"
13
+ )
14
+ super
15
+ end
16
+
17
+ def value
18
+ Array(super)
19
+ end
20
+
21
+ private
22
+
23
+ def valid?
24
+ value.all? { |role_name| (role_name.is_a?(Symbol) || role_name.is_a?(String)) && role_name.to_s.match?(REGEX) }
25
+ end
26
+
27
+ def processed_value
28
+ value.map(&:to_sym)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rabarber
4
+ module Input
5
+ module Types
6
+ class Booleans < Rabarber::Input::Base
7
+ private
8
+
9
+ def valid?
10
+ [true, false].include?(value)
11
+ end
12
+
13
+ def processed_value
14
+ value
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rabarber
4
+ module Input
5
+ module Types
6
+ class Procs < Rabarber::Input::Base
7
+ private
8
+
9
+ def valid?
10
+ value.is_a?(Proc)
11
+ end
12
+
13
+ def processed_value
14
+ value
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rabarber
4
+ module Input
5
+ module Types
6
+ class Symbols < Rabarber::Input::Base
7
+ private
8
+
9
+ def valid?
10
+ (value.is_a?(Symbol) || value.is_a?(String)) && value.present?
11
+ end
12
+
13
+ def processed_value
14
+ value.to_sym
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rabarber
4
+ module Missing
5
+ class Actions < Rabarber::Missing::Base
6
+ private
7
+
8
+ def check_controller_rules
9
+ nil
10
+ end
11
+
12
+ def check_action_rules
13
+ action_rules.each do |controller, controller_action_rules|
14
+ missing_actions = controller_action_rules.map(&:action) - controller.action_methods.map(&:to_sym)
15
+ missing_list << Rabarber::Missing::Item.new(missing_actions, controller, nil) if missing_actions.present?
16
+ end
17
+ end
18
+
19
+ def configuration_name
20
+ :when_actions_missing
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rabarber
4
+ module Missing
5
+ class Base
6
+ attr_reader :controller
7
+
8
+ def initialize(controller = nil)
9
+ @controller = controller
10
+ end
11
+
12
+ def handle
13
+ check_controller_rules
14
+ check_action_rules
15
+
16
+ return if missing_list.empty?
17
+
18
+ missing_list.each do |item|
19
+ Rabarber::Configuration.instance.public_send(configuration_name).call(
20
+ item.missing, controller: item.controller, action: item.action
21
+ )
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def check_controller_rules
28
+ raise NotImplementedError
29
+ end
30
+
31
+ def check_action_rules
32
+ raise NotImplementedError
33
+ end
34
+
35
+ def configuration_name
36
+ raise NotImplementedError
37
+ end
38
+
39
+ def missing_list
40
+ @missing_list ||= []
41
+ end
42
+
43
+ def controller_rules
44
+ if controller
45
+ { controller => Rabarber::Permissions.controller_rules[controller] }
46
+ else
47
+ Rabarber::Permissions.controller_rules
48
+ end
49
+ end
50
+
51
+ def action_rules
52
+ if controller
53
+ { controller => Rabarber::Permissions.action_rules[controller] }
54
+ else
55
+ Rabarber::Permissions.action_rules
56
+ end
57
+ end
58
+ end
59
+
60
+ Item = Struct.new(:missing, :controller, :action)
61
+ end
62
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rabarber
4
+ module Missing
5
+ class Roles < Rabarber::Missing::Base
6
+ private
7
+
8
+ def check_controller_rules
9
+ controller_rules.each do |controller, controller_rule|
10
+ missing_roles = controller_rule.roles - all_roles if controller_rule.present?
11
+ missing_list << Rabarber::Missing::Item.new(missing_roles, controller, nil) if missing_roles.present?
12
+ end
13
+ end
14
+
15
+ def check_action_rules
16
+ action_rules.each do |controller, controller_action_rules|
17
+ controller_action_rules.each do |action_rule|
18
+ missing_roles = action_rule.roles - all_roles
19
+ if missing_roles.any?
20
+ missing_list << Rabarber::Missing::Item.new(missing_roles, controller, action_rule.action)
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ def configuration_name
27
+ :when_roles_missing
28
+ end
29
+
30
+ def all_roles
31
+ @all_roles ||= Rabarber::Role.names
32
+ end
33
+ end
34
+ end
35
+ end
@@ -5,7 +5,9 @@ module Rabarber
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
- raise Error, "Rabarber::HasRoles can only be included once" if defined?(@@included) && @@included != name
8
+ if defined?(@@included) && @@included != name
9
+ raise Rabarber::Error, "Rabarber::HasRoles can only be included once"
10
+ end
9
11
 
10
12
  @@included = name
11
13
 
@@ -19,26 +21,30 @@ module Rabarber
19
21
  end
20
22
 
21
23
  def has_role?(*role_names)
22
- (roles & RoleNames.pre_process(role_names)).any?
24
+ (roles & process_role_names(role_names)).any?
23
25
  end
24
26
 
25
27
  def assign_roles(*role_names, create_new: true)
26
- roles_to_assign = RoleNames.pre_process(role_names)
28
+ roles_to_assign = process_role_names(role_names)
27
29
 
28
30
  create_new_roles(roles_to_assign) if create_new
29
31
 
30
- rabarber_roles << Role.where(name: roles_to_assign) - rabarber_roles
32
+ rabarber_roles << Rabarber::Role.where(name: roles_to_assign) - rabarber_roles
31
33
  end
32
34
 
33
35
  def revoke_roles(*role_names)
34
- self.rabarber_roles = rabarber_roles - Role.where(name: RoleNames.pre_process(role_names))
36
+ self.rabarber_roles = rabarber_roles - Rabarber::Role.where(name: process_role_names(role_names))
35
37
  end
36
38
 
37
39
  private
38
40
 
39
41
  def create_new_roles(role_names)
40
- new_roles = role_names - Role.names
41
- new_roles.each { |role_name| Role.create!(name: role_name) }
42
+ new_roles = role_names - Rabarber::Role.names
43
+ new_roles.each { |role_name| Rabarber::Role.create!(name: role_name) }
44
+ end
45
+
46
+ def process_role_names(role_names)
47
+ Rabarber::Input::Roles.new(role_names).process
42
48
  end
43
49
  end
44
50
  end
@@ -4,7 +4,7 @@ module Rabarber
4
4
  class Role < ActiveRecord::Base
5
5
  self.table_name = "rabarber_roles"
6
6
 
7
- validates :name, presence: true, uniqueness: true, format: { with: RoleNames::REGEX }
7
+ validates :name, presence: true, uniqueness: true, format: { with: Rabarber::Input::Roles::REGEX }
8
8
 
9
9
  def self.names
10
10
  pluck(:name).map(&:to_sym)
@@ -15,8 +15,8 @@ module Rabarber
15
15
  @storage = { controller_rules: Hash.new({}), action_rules: Hash.new([]) }
16
16
  end
17
17
 
18
- def self.write(controller, action, roles, dynamic_rule, negated_dynamic_rule)
19
- rule = Rule.new(action, roles, dynamic_rule, negated_dynamic_rule)
18
+ def self.add(controller, action, roles, dynamic_rule, negated_dynamic_rule)
19
+ rule = Rabarber::Rule.new(action, roles, dynamic_rule, negated_dynamic_rule)
20
20
 
21
21
  if action
22
22
  instance.storage[:action_rules][controller] += [rule]
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/railtie"
4
+
5
+ module Rabarber
6
+ class Railtie < Rails::Railtie
7
+ initializer "rabarber.after_initialize" do |app|
8
+ app.config.after_initialize do
9
+ Rabarber::Missing::Actions.new.handle
10
+ Rabarber::Missing::Roles.new.handle
11
+ end
12
+ end
13
+ end
14
+ end
data/lib/rabarber/rule.rb CHANGED
@@ -5,10 +5,10 @@ module Rabarber
5
5
  attr_reader :action, :roles, :dynamic_rule, :negated_dynamic_rule
6
6
 
7
7
  def initialize(action, roles, dynamic_rule, negated_dynamic_rule)
8
- @action = pre_process_action(action)
9
- @roles = RoleNames.pre_process(Array(roles))
10
- @dynamic_rule = pre_process_dynamic_rule(dynamic_rule)
11
- @negated_dynamic_rule = pre_process_dynamic_rule(negated_dynamic_rule)
8
+ @action = action
9
+ @roles = Array(roles)
10
+ @dynamic_rule = dynamic_rule
11
+ @negated_dynamic_rule = negated_dynamic_rule
12
12
  end
13
13
 
14
14
  def verify_access(user_roles, dynamic_rule_receiver, action_name = nil)
@@ -20,7 +20,7 @@ module Rabarber
20
20
  end
21
21
 
22
22
  def roles_permitted?(user_roles)
23
- return false if ::Rabarber::Configuration.instance.must_have_roles && user_roles.empty?
23
+ return false if Rabarber::Configuration.instance.must_have_roles && user_roles.empty?
24
24
 
25
25
  roles.empty? || (roles & user_roles).any?
26
26
  end
@@ -44,19 +44,5 @@ module Rabarber
44
44
 
45
45
  is_negated ? !result : result
46
46
  end
47
-
48
- def pre_process_action(action)
49
- return action.to_sym if (action.is_a?(String) || action.is_a?(Symbol)) && action.present?
50
- return action if action.nil?
51
-
52
- raise InvalidArgumentError, "Action name must be a Symbol or a String"
53
- end
54
-
55
- def pre_process_dynamic_rule(rule)
56
- return rule.to_sym if (rule.is_a?(String) || rule.is_a?(Symbol)) && rule.present?
57
- return rule if rule.nil? || rule.is_a?(Proc)
58
-
59
- raise InvalidArgumentError, "Dynamic rule must be a Symbol, a String, or a Proc"
60
- end
61
47
  end
62
48
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rabarber
4
- VERSION = "1.1.0"
4
+ VERSION = "1.2.0"
5
5
  end
data/lib/rabarber.rb CHANGED
@@ -6,7 +6,17 @@ require_relative "rabarber/configuration"
6
6
  require "active_record"
7
7
  require "active_support"
8
8
 
9
- require_relative "rabarber/role_names"
9
+ require_relative "rabarber/input/base"
10
+ require_relative "rabarber/input/actions"
11
+ require_relative "rabarber/input/dynamic_rules"
12
+ require_relative "rabarber/input/roles"
13
+ require_relative "rabarber/input/types/booleans"
14
+ require_relative "rabarber/input/types/procs"
15
+ require_relative "rabarber/input/types/symbols"
16
+
17
+ require_relative "rabarber/missing/base"
18
+ require_relative "rabarber/missing/actions"
19
+ require_relative "rabarber/missing/roles"
10
20
 
11
21
  require_relative "rabarber/controllers/concerns/authorization"
12
22
  require_relative "rabarber/helpers/helpers"
@@ -14,14 +24,16 @@ require_relative "rabarber/models/concerns/has_roles"
14
24
  require_relative "rabarber/models/role"
15
25
  require_relative "rabarber/permissions"
16
26
 
27
+ require_relative "rabarber/railtie"
28
+
17
29
  module Rabarber
18
30
  module_function
19
31
 
32
+ class Error < StandardError; end
33
+ class ConfigurationError < Rabarber::Error; end
34
+ class InvalidArgumentError < Rabarber::Error; end
35
+
20
36
  def configure
21
- yield(Configuration.instance)
37
+ yield(Rabarber::Configuration.instance)
22
38
  end
23
-
24
- class Error < StandardError; end
25
- class ConfigurationError < Error; end
26
- class InvalidArgumentError < Error; end
27
39
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rabarber
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - enjaku4
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2024-01-18 00:00:00.000000000 Z
12
+ date: 2024-01-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -42,10 +42,20 @@ files:
42
42
  - lib/rabarber/configuration.rb
43
43
  - lib/rabarber/controllers/concerns/authorization.rb
44
44
  - lib/rabarber/helpers/helpers.rb
45
+ - lib/rabarber/input/actions.rb
46
+ - lib/rabarber/input/base.rb
47
+ - lib/rabarber/input/dynamic_rules.rb
48
+ - lib/rabarber/input/roles.rb
49
+ - lib/rabarber/input/types/booleans.rb
50
+ - lib/rabarber/input/types/procs.rb
51
+ - lib/rabarber/input/types/symbols.rb
52
+ - lib/rabarber/missing/actions.rb
53
+ - lib/rabarber/missing/base.rb
54
+ - lib/rabarber/missing/roles.rb
45
55
  - lib/rabarber/models/concerns/has_roles.rb
46
56
  - lib/rabarber/models/role.rb
47
57
  - lib/rabarber/permissions.rb
48
- - lib/rabarber/role_names.rb
58
+ - lib/rabarber/railtie.rb
49
59
  - lib/rabarber/rule.rb
50
60
  - lib/rabarber/version.rb
51
61
  - rabarber.gemspec
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Rabarber
4
- module RoleNames
5
- module_function
6
-
7
- REGEX = /\A[a-z0-9_]+\z/
8
-
9
- def pre_process(role_names)
10
- return role_names.map(&:to_sym) if role_names.all? do |role_name|
11
- (role_name.is_a?(Symbol) || role_name.is_a?(String)) && role_name.to_s.match?(REGEX)
12
- end
13
-
14
- raise(
15
- InvalidArgumentError,
16
- "Role names must be Symbols or Strings and may only contain lowercase letters, numbers and underscores"
17
- )
18
- end
19
- end
20
- end