accessly 1.0.1 → 1.0.2
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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +24 -0
- data/lib/accessly/policy/base.rb +90 -75
- data/lib/accessly/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 96505b522e737820634c4c02ab4c861880008a70
|
4
|
+
data.tar.gz: eee707f0a8667c4e9f383e827197f64db141412f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 504dd75a1ce9ae60c89dd3e335de18cb7ef46e45bc2a39d67e07407d94eec0daffbeedcf70ac8a045cdb26c5be2c584c3e756cbbca46757ac9826281b3ad00dd
|
7
|
+
data.tar.gz: 511e3129de53be6bb92c8519db2dd9fc29b392851337dfb38d0104116eb7d56cd0d85f4957465bfcb15b6817e1a602225b5a42e88df56d06aecaafc65ba81ae5
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -64,6 +64,18 @@ class ApplicationFeaturePolicy < Accessly::Policy::Base
|
|
64
64
|
end
|
65
65
|
```
|
66
66
|
|
67
|
+
#### ACTIONS
|
68
|
+
|
69
|
+
Accessly policies rely on a definition of `actions` and/or `actions_on_objects` for effective use. This example uses `actions` which represent a "permission" that can be granted to an actor for later validation within your app's business logic.
|
70
|
+
|
71
|
+
- `actions` map a symbol to an integer value.
|
72
|
+
- An `action` value should be a unique integer within each policy.
|
73
|
+
- removing/editing `actions` and values can have negative consequences if the underlying data is not migrated
|
74
|
+
|
75
|
+
Defined policy `actions` become part of the policy API. (see examples below)
|
76
|
+
|
77
|
+
#### Policy API Example
|
78
|
+
|
67
79
|
With this policy we can `grant` permissions to a user
|
68
80
|
|
69
81
|
```ruby
|
@@ -107,6 +119,18 @@ class UserPolicy < Accessly::Policy::Base
|
|
107
119
|
end
|
108
120
|
```
|
109
121
|
|
122
|
+
#### ACTIONS ON OBJECTS
|
123
|
+
|
124
|
+
Accessly policies rely on a definition of `actions` and/or `actions_on_objects` for effective use. This example uses `actions_on_objects` which associate a "permission" with an object in your system. The "object" is typically an ActiveRecord object.
|
125
|
+
|
126
|
+
- `actions_on_objects` map a symbol to an integer value.
|
127
|
+
- An `actions_on_objects` value should be a unique integer within each policy.
|
128
|
+
- removing/editing `actions_on_objects` and values can have negative consequences if the underlying data is not migrated
|
129
|
+
|
130
|
+
Defined policy `actions_on_objects` become part of the policy API. (see examples below)
|
131
|
+
|
132
|
+
#### Policy API Example
|
133
|
+
|
110
134
|
We differentiate permissions by a `namespace` which by default is the name of your policy class. However,
|
111
135
|
it may be necessary to override the default behavior represented in the above example.
|
112
136
|
|
data/lib/accessly/policy/base.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
module Accessly
|
2
2
|
module Policy
|
3
3
|
class Base
|
4
|
+
# Module that will hold our meta-programmed action methods just above
|
5
|
+
# the policy class in the inheritance hierarchy; allowing for them to
|
6
|
+
# be overridden in the policy.
|
7
|
+
ACTIONS_MODULE = :Actions
|
4
8
|
|
5
9
|
attr_reader :actor
|
6
10
|
|
@@ -8,17 +12,82 @@ module Accessly
|
|
8
12
|
@actor = actor
|
9
13
|
end
|
10
14
|
|
15
|
+
# Meta-programs action methods from actions supplied.
|
16
|
+
# Used in policies as a DSL to declare actions.
|
17
|
+
#
|
18
|
+
# This defines the actions on the `actions_module` so that they are
|
19
|
+
# positioned higher in the inheritance tree than methods defined on the
|
20
|
+
# class itself. This will allow us to define methods that override these
|
21
|
+
# base methods and call `super`.
|
22
|
+
#
|
23
|
+
# @param actions [Hash] the actions to define on the policy
|
24
|
+
#
|
25
|
+
# @example Define Actions
|
26
|
+
#
|
27
|
+
# # This example causes the following methods to be defined:
|
28
|
+
# # some_action? : Returns true if the actor has the some_action
|
29
|
+
# # permission, false otherwise
|
30
|
+
# # flip_the_flop? : Returns true if the actor has the flip_the_flop
|
31
|
+
# # permission, false otherwise
|
32
|
+
# # create? : Returns true if the actor has the create permission, false
|
33
|
+
# # otherwise
|
34
|
+
# actions(
|
35
|
+
# some_action: 1,
|
36
|
+
# flip_the_flop: 2,
|
37
|
+
# create: 3
|
38
|
+
# )
|
39
|
+
#
|
40
|
+
# @return [Hash] actions
|
11
41
|
def self.actions(actions)
|
12
42
|
_actions.merge!(actions)
|
13
43
|
actions.each do |action, action_id|
|
14
|
-
|
44
|
+
actions_module.module_eval do
|
45
|
+
define_method(:"#{action}?") do |*args|
|
46
|
+
_can_do_action?(action, action_id, args.first)
|
47
|
+
end
|
48
|
+
end
|
15
49
|
end
|
16
50
|
end
|
17
51
|
|
52
|
+
# Meta-programs action_on_objects methods from the actions supplied.
|
53
|
+
# Used in policies as a DSL to declare actions on objects.
|
54
|
+
# It is different from actions in that it will also define a method
|
55
|
+
# for listing all objects authorized with this action for the given
|
56
|
+
# actor and that these actions will always be associated not only with
|
57
|
+
# an actor, but with an object of the action.
|
58
|
+
#
|
59
|
+
# @param actions_on_objects [Hash] the actions on objects to define
|
60
|
+
# on the policy
|
61
|
+
#
|
62
|
+
# @example Define Actions On Objects
|
63
|
+
#
|
64
|
+
# # This example causes the following methods to be defined:
|
65
|
+
# # edit : Returns an ActiveRecord::Relation of the objects on which
|
66
|
+
# # the actor has the edit permission
|
67
|
+
# # edit?(object) : Returns true if the actor has the edit permission
|
68
|
+
# # on the given object, false otherwise
|
69
|
+
# # show : Returns an ActiveRecord::Relation of the objects on which
|
70
|
+
# # the actor has the show permission
|
71
|
+
# # show?(object) : Returns true if the actor has the show permission
|
72
|
+
# # on the given object, false otherwise
|
73
|
+
# actions_on_objects(
|
74
|
+
# edit: 1,
|
75
|
+
# show: 2
|
76
|
+
# )
|
77
|
+
#
|
78
|
+
# @return [Hash] actions_on_objects
|
18
79
|
def self.actions_on_objects(actions_on_objects)
|
19
80
|
_actions_on_objects.merge!(actions_on_objects)
|
20
81
|
actions_on_objects.each do |action, action_id|
|
21
|
-
|
82
|
+
actions_module.module_eval do
|
83
|
+
define_method(:"#{action}?") do |*args|
|
84
|
+
_can_do_action?(action, action_id, args.first)
|
85
|
+
end
|
86
|
+
|
87
|
+
define_method(action) do |*args|
|
88
|
+
_list_for_action(action, action_id)
|
89
|
+
end
|
90
|
+
end
|
22
91
|
end
|
23
92
|
end
|
24
93
|
|
@@ -102,85 +171,31 @@ module Accessly
|
|
102
171
|
|
103
172
|
private
|
104
173
|
|
105
|
-
|
106
|
-
|
107
|
-
|
174
|
+
# Accessor for the actions module that will hold our meta-programmed
|
175
|
+
# methods.
|
176
|
+
# We put these methods in this module so that they are positioned
|
177
|
+
# above the policy in the inheritance chain. We can then override
|
178
|
+
# the methods in our policy as needed and call super to access the
|
179
|
+
# previous definition.
|
180
|
+
#
|
181
|
+
# @return [ACTIONS_MODULE] the module for holding actions currently
|
182
|
+
# defined on this class.
|
183
|
+
def self.actions_module
|
184
|
+
if const_defined?(ACTIONS_MODULE, _search_ancestors = false)
|
185
|
+
mod = const_get(ACTIONS_MODULE)
|
108
186
|
else
|
109
|
-
|
187
|
+
mod = const_set(ACTIONS_MODULE, Module.new)
|
188
|
+
include mod
|
110
189
|
end
|
111
|
-
end
|
112
190
|
|
113
|
-
|
114
|
-
# in the format `action_name?`. If so, this calls that method with
|
115
|
-
# the given arguments.
|
116
|
-
def method_missing(method_name, *args)
|
117
|
-
action_method_name = _resolve_action_method_name(method_name)
|
118
|
-
if action_method_name.nil?
|
119
|
-
super
|
120
|
-
else
|
121
|
-
send(action_method_name, *args)
|
122
|
-
end
|
191
|
+
mod
|
123
192
|
end
|
124
193
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
# one of those formats, this assumes the caller is not calling
|
129
|
-
# an action or list method and returns nil.
|
130
|
-
def _resolve_action_method_name(method_name)
|
131
|
-
action_method_match = /\A(\w+)(\??)\z/.match(method_name)
|
132
|
-
|
133
|
-
return nil if action_method_match.nil? || action_method_match[1].nil?
|
134
|
-
|
135
|
-
action_name = action_method_match[1].to_sym
|
136
|
-
is_predicate = action_method_match[2] == "?"
|
137
|
-
|
138
|
-
if !_action_defined?(action_name)
|
139
|
-
nil
|
140
|
-
elsif is_predicate
|
141
|
-
_action_method_name(action_name)
|
194
|
+
def _get_action_id(action, object_id = nil)
|
195
|
+
if object_id.nil?
|
196
|
+
_get_general_action_id!(action)
|
142
197
|
else
|
143
|
-
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
# The implementation for action methods follow the naming format
|
148
|
-
# `_resolve_action_name`. This is to allow child Policies to override
|
149
|
-
# the action method and still be able to call `super` when they
|
150
|
-
# need to call the base implementation of the action method.
|
151
|
-
def self._action_method_name(action_name)
|
152
|
-
"_resolve_#{action_name}"
|
153
|
-
end
|
154
|
-
|
155
|
-
def _action_method_name(action_name)
|
156
|
-
self.class._action_method_name(action_name)
|
157
|
-
end
|
158
|
-
|
159
|
-
# The implementation for list methods follow the naming format
|
160
|
-
# `_list_action_name`. This is to allow child Policies to override
|
161
|
-
# the list method and still be able to call `super` when they
|
162
|
-
# need to call the base implementation of the lsit method.
|
163
|
-
def self._action_list_method_name(action_name)
|
164
|
-
"_list_#{action_name}"
|
165
|
-
end
|
166
|
-
|
167
|
-
def _action_list_method_name(action_name)
|
168
|
-
self.class._action_list_method_name(action_name)
|
169
|
-
end
|
170
|
-
|
171
|
-
# Defines the action method on the Policy class for the given
|
172
|
-
# action name.
|
173
|
-
def self._define_action_methods(action, action_id)
|
174
|
-
unless method_defined?(_action_method_name(action))
|
175
|
-
define_method(_action_method_name(action)) do |*args|
|
176
|
-
_can_do_action?(action, action_id, args.first)
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
unless method_defined?(_action_list_method_name(action))
|
181
|
-
define_method(_action_list_method_name(action)) do |*args|
|
182
|
-
_list_for_action(action, action_id)
|
183
|
-
end
|
198
|
+
_get_action_on_object_id!(action)
|
184
199
|
end
|
185
200
|
end
|
186
201
|
|
data/lib/accessly/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: accessly
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aaron Milam
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: exe
|
12
12
|
cert_chain: []
|
13
|
-
date: 2018-
|
13
|
+
date: 2018-10-12 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activerecord
|