ez-permissions 0.3.0 → 0.4.4
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/README.md +38 -12
- data/lib/ez/permissions/api/authorize.rb +10 -0
- data/lib/ez/permissions/api/authorize/model_permissions.rb +33 -0
- data/lib/ez/permissions/api/models.rb +9 -0
- data/lib/ez/permissions/dsl.rb +1 -1
- data/lib/ez/permissions/resource.rb +2 -1
- data/lib/ez/permissions/version.rb +1 -1
- data/lib/tasks/ez/permissions_tasks.rake +4 -4
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c103819ff5b91d66f0f956545f2b0c1366e4ff076f953370e34e2e4c3685c099
|
4
|
+
data.tar.gz: f8094eb993fff840aac16397516ecaff77f121cecd09d654f7b3316113199b45
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 75e8986de02432aa15c5135fa5821ca390daf446f4dfcef6c936bb3708179798b8b964138ce406142516fc0042aabed6516840fab1440318741973826d04e17b
|
7
|
+
data.tar.gz: 2eb3c3a15fb6e31dc47dccc28ffba3482a53d5face7757ed3f4269112346f5f739c6968d6cebbc2c71fe089c3c64a4b291a6ed15993ff713e2da8877dc649e08
|
data/README.md
CHANGED
@@ -7,9 +7,9 @@
|
|
7
7
|
**Ez Permissions** (read as "easy permissions") - one of the [ez-engines](https://github.com/ez-engines) collection that helps easily add permissions interface to your [Rails](http://rubyonrails.org/) application.
|
8
8
|
|
9
9
|
- Most advanced RBAC model:
|
10
|
-
- Flexible tool with simple DSL and
|
10
|
+
- Flexible tool with simple DSL and configuration
|
11
11
|
- All in one solution
|
12
|
-
-
|
12
|
+
- Convention over configuration principles.
|
13
13
|
- Depends on [ez-core](https://github.com/ez-engines/ez-core)
|
14
14
|
|
15
15
|
## Installation
|
@@ -36,7 +36,7 @@ Ez::Permissions.configure do |config|
|
|
36
36
|
config.models_roles_table_name = 'my_model_roles'
|
37
37
|
config.permissions_roles_table_name = 'my_permissions_roles'
|
38
38
|
|
39
|
-
# Suppress
|
39
|
+
# Suppress STDOUT messages for test environment
|
40
40
|
config.mute_stdout = true if Rails.env.test?
|
41
41
|
|
42
42
|
# Define your custom callbacks
|
@@ -61,7 +61,7 @@ rails generate ez:permissions:migrations
|
|
61
61
|
|
62
62
|
## DSL
|
63
63
|
|
64
|
-
Simple DSL for
|
64
|
+
Simple DSL for definition of permission relationships
|
65
65
|
```ruby
|
66
66
|
Ez::Permissions::DSL.define do |setup|
|
67
67
|
# You need add all resources of your application and possible actions
|
@@ -72,8 +72,8 @@ Ez::Permissions::DSL.define do |setup|
|
|
72
72
|
setup.add :permissions, actions: %i[crud my_custom_action]
|
73
73
|
|
74
74
|
# Actions option are not required. In such case you add all crud actions by default
|
75
|
-
setup.add :users
|
76
|
-
setup.add :projects
|
75
|
+
setup.add :users, group: :accounts # You can group resources
|
76
|
+
setup.add :projects # Resource without a group will get "others" group
|
77
77
|
end
|
78
78
|
```
|
79
79
|
|
@@ -89,7 +89,7 @@ user = User.first
|
|
89
89
|
|
90
90
|
# User model become permission model
|
91
91
|
user.roles #=> [application level roles]
|
92
|
-
user.assigned_roles #=> [user owned roles,
|
92
|
+
user.assigned_roles #=> [user owned roles, global and scoped]
|
93
93
|
user.permissions #=> [user available permissions through assigned_roles]
|
94
94
|
```
|
95
95
|
|
@@ -146,6 +146,10 @@ Permissions.includes_role?(user, :admin)
|
|
146
146
|
# Check if user includes scoped role
|
147
147
|
project = Project.first
|
148
148
|
Permissions.includes_role?(user, :manager, scoped: project)
|
149
|
+
|
150
|
+
# List users with particular role in particular scope
|
151
|
+
project = Project.first
|
152
|
+
Permissions.list_by_role(:manager, scoped: project)
|
149
153
|
```
|
150
154
|
|
151
155
|
### Permissions
|
@@ -180,7 +184,7 @@ end
|
|
180
184
|
# otherwise you will get an exception
|
181
185
|
Ez::Permissions::NotAuthorized
|
182
186
|
|
183
|
-
# Both .
|
187
|
+
# Both .authorize and .authorize! methods can be used without blocks.
|
184
188
|
|
185
189
|
# if you don't want raise exception, just use
|
186
190
|
Permissions.authorize(user, :create, :users) { puts 'Yeahh!' } #=> false
|
@@ -191,11 +195,33 @@ Permissions.can?(user, :create, :users) => # true
|
|
191
195
|
Permissions.can?(user, :create, :users, scoped: project) => # false
|
192
196
|
```
|
193
197
|
|
198
|
+
### Caching user permissions
|
199
|
+
|
200
|
+
If in one HTTP request (e.g. navigation menu rendering) you don't want to hit the database with dozens of queries, you can cache all user permission in a hash
|
201
|
+
|
202
|
+
```ruby
|
203
|
+
user_permissions = Permissions.model_permissions_map(user)
|
204
|
+
user_permissions # => #<Ez::Permissions::API::Authorize::ModelPermissions...
|
205
|
+
|
206
|
+
# You can fetch permissions as a hash
|
207
|
+
user_permissions.permissions_map # => { :read_users => true}
|
208
|
+
|
209
|
+
# and the in your code just fetch by the key:
|
210
|
+
if user_permissions.permissions_map[:read_users]
|
211
|
+
# execute authorized code
|
212
|
+
end
|
213
|
+
|
214
|
+
# or user #can? and #authorize! helper methods
|
215
|
+
user_permissions.can?(:read, :users) # => true
|
216
|
+
user_permissions.can?(:create, :users) # => false
|
217
|
+
user_permissions.authorize!(:create, :users) # => raise Ez::Permissions::NotAuthorized
|
218
|
+
```
|
219
|
+
|
194
220
|
### Testing
|
195
221
|
EzPermissions ships with bunch of RSpec helper methods that helps mock permission.
|
196
222
|
For large test suite (more than 5000 specs) it saves up to 30% of test runs time.
|
197
223
|
|
198
|
-
Add test helpers
|
224
|
+
Add test helpers to your rspec config
|
199
225
|
```ruby
|
200
226
|
require 'ez/permissions/rspec_helpers'
|
201
227
|
|
@@ -226,7 +252,7 @@ mock_model_role(:worker, user)
|
|
226
252
|
mock_permission(:users, :create)
|
227
253
|
```
|
228
254
|
|
229
|
-
###
|
255
|
+
### Cleanup redundant permissions
|
230
256
|
If you changed your permissions DSL and removed redundant resources and actions
|
231
257
|
|
232
258
|
```sh
|
@@ -234,7 +260,7 @@ rake ez:permissions:outdated # display list of outdated permissions
|
|
234
260
|
rake ez:permissions:cleanup # remove outdated permissions from the DB
|
235
261
|
```
|
236
262
|
|
237
|
-
###
|
263
|
+
### Keep it explicit!
|
238
264
|
You can wonder, why we just not add authorization methods to user instance, like:
|
239
265
|
```ruby
|
240
266
|
user.can?(:something)
|
@@ -248,7 +274,7 @@ Of course, you can use them as mixins, but it's up to you.
|
|
248
274
|
- User can has role in scope of some resource (Project, Company, Business, etc.)
|
249
275
|
- User can has role in global scope (without scope)
|
250
276
|
- If user want access data in scope of resource - user must has assigned role scoped for this resource
|
251
|
-
- If user want access data in global scope - user must has assigned role
|
277
|
+
- If user want access data in global scope - user must has assigned role without any scoped resource (global role)
|
252
278
|
- User with global role - can't access scoped resources.
|
253
279
|
- User with scoped role - can't access global resources.
|
254
280
|
|
@@ -1,9 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'authorize/model_permissions'
|
4
|
+
|
3
5
|
module Ez
|
4
6
|
module Permissions
|
5
7
|
module API
|
6
8
|
module Authorize
|
9
|
+
def model_permissions(model)
|
10
|
+
ModelPermissions.new(
|
11
|
+
model.permissions.each_with_object({}) do |permission, acum|
|
12
|
+
acum["#{permission.action}_#{permission.resource}".to_sym] = true
|
13
|
+
end
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
7
17
|
def authorize!(model, *actions, resource, scoped: nil, &block)
|
8
18
|
authorize(model, *actions, resource, scoped: scoped, raise_exception: true, &block)
|
9
19
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ez
|
4
|
+
module Permissions
|
5
|
+
module API
|
6
|
+
module Authorize
|
7
|
+
class ModelPermissions
|
8
|
+
attr_reader :permissions_map
|
9
|
+
|
10
|
+
def initialize(permissions_map)
|
11
|
+
@permissions_map = permissions_map
|
12
|
+
end
|
13
|
+
|
14
|
+
def can?(action_name, resource_name)
|
15
|
+
permissions_map[to_key(action_name, resource_name)] == true
|
16
|
+
end
|
17
|
+
|
18
|
+
def authorize!(action_name, resource_name)
|
19
|
+
permissions_map.fetch(to_key(action_name, resource_name))
|
20
|
+
rescue KeyError
|
21
|
+
raise Ez::Permissions::NotAuthorizedError
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def to_key(action_name, resource_name)
|
27
|
+
"#{action_name}_#{resource_name}".to_sym
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -26,6 +26,15 @@ module Ez
|
|
26
26
|
model_role(role, model, scoped) ? true : false
|
27
27
|
end
|
28
28
|
|
29
|
+
def list_by_role(role_name, scoped: nil)
|
30
|
+
role = Ez::Permissions::API.get_role!(role_name)
|
31
|
+
|
32
|
+
Ez::Permissions::ModelRole.where(
|
33
|
+
role: role,
|
34
|
+
scoped: scoped
|
35
|
+
).map(&:model)
|
36
|
+
end
|
37
|
+
|
29
38
|
private
|
30
39
|
|
31
40
|
def model_role(role, model, scoped)
|
data/lib/ez/permissions/dsl.rb
CHANGED
@@ -42,7 +42,7 @@ module Ez
|
|
42
42
|
return unless seed_to_db(resource)
|
43
43
|
|
44
44
|
message(
|
45
|
-
"Resource [#{name}] has been successfully
|
45
|
+
"Resource [#{name}] has been successfully registered with actions: [#{resource.actions.join(', ')}]",
|
46
46
|
'SUCCESS'
|
47
47
|
)
|
48
48
|
end
|
@@ -5,12 +5,13 @@ module Ez
|
|
5
5
|
class Resource
|
6
6
|
ACTIONS = %i[create read update delete].freeze
|
7
7
|
|
8
|
-
attr_reader :name, :model, :actions
|
8
|
+
attr_reader :name, :model, :actions, :group
|
9
9
|
|
10
10
|
def initialize(name, options = {})
|
11
11
|
@name = name
|
12
12
|
@model = options.fetch(:model, nil)
|
13
13
|
@actions = process_actions(options.fetch(:actions, []))
|
14
|
+
@group = options.fetch(:group, :others)
|
14
15
|
end
|
15
16
|
|
16
17
|
def <=>(other)
|
@@ -7,8 +7,8 @@ namespace :ez do
|
|
7
7
|
Ez::Permissions::Permission.find_each do |permission|
|
8
8
|
next if Ez::Permissions::DSL.resource_action?(permission.resource, permission.action)
|
9
9
|
|
10
|
-
STDOUT.puts
|
11
|
-
|
10
|
+
STDOUT.puts '[WARNING] Ez::Permissions:'\
|
11
|
+
"Permission##{permission.id} [#{permission.resource} -> #{permission.action}] is redundant"
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
@@ -17,8 +17,8 @@ namespace :ez do
|
|
17
17
|
next if Ez::Permissions::DSL.resource_action?(permission.resource, permission.action)
|
18
18
|
|
19
19
|
permission.destroy
|
20
|
-
STDOUT.puts
|
21
|
-
|
20
|
+
STDOUT.puts '[WARNING] Ez::Permissions:'\
|
21
|
+
"Permission##{permission.id} [#{permission.resource} -> #{permission.action}] is removed"
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ez-permissions
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Volodya Sveredyuk
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-06-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ez-core
|
@@ -176,6 +176,7 @@ files:
|
|
176
176
|
- lib/ez/permissions.rb
|
177
177
|
- lib/ez/permissions/api.rb
|
178
178
|
- lib/ez/permissions/api/authorize.rb
|
179
|
+
- lib/ez/permissions/api/authorize/model_permissions.rb
|
179
180
|
- lib/ez/permissions/api/models.rb
|
180
181
|
- lib/ez/permissions/api/permissions.rb
|
181
182
|
- lib/ez/permissions/api/roles.rb
|
@@ -207,7 +208,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
207
208
|
- !ruby/object:Gem::Version
|
208
209
|
version: '0'
|
209
210
|
requirements: []
|
210
|
-
rubygems_version: 3.
|
211
|
+
rubygems_version: 3.1.2
|
211
212
|
signing_key:
|
212
213
|
specification_version: 4
|
213
214
|
summary: Easy permissions engine for Rails app.
|