rabarber 1.1.0 → 1.2.0

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