ez-permissions 0.1.2 → 0.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 +4 -4
- data/README.md +47 -0
- data/lib/ez/permissions/api/authorize.rb +7 -3
- data/lib/ez/permissions/api/models.rb +13 -1
- data/lib/ez/permissions/rspec_helpers.rb +130 -0
- data/lib/ez/permissions/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e17eb8ad5fd168be1fc8a40908d613466f05df2cf724ad2989e8eb0ea98068b0
|
4
|
+
data.tar.gz: 42ab1e2a10d6c279139e034ecefbdc1b60e36ed8de464904d4f0fb067650c971
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7b8b712c799ce127b6ec8e2d3a5f95e8b2d79a36c693f846263dc18f0faf256cadc0c92a792dee8e15b054a1beb77c49f8d62ec3438187f1b82efbed9507b784
|
7
|
+
data.tar.gz: 901a12fb2c742deb2f17d3dab4082e8bdeab288101d34a1434ad68dc16d860e456c325567345374494a6f2930a022d7c1c58ec7c9771fe29b313eaaa1d701621
|
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# Ez::Permissions
|
2
2
|
|
3
3
|
[](https://badge.fury.io/rb/ez-permissions)
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
4
5
|
[](https://travis-ci.org/ez-engines/ez-permissions)
|
5
6
|
|
6
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.
|
@@ -132,6 +133,13 @@ Permissions.assign_role(user, :admin, scoped: project)
|
|
132
133
|
|
133
134
|
# Reject user role in global scope, but project admin role will stay
|
134
135
|
Permissions.reject_role(user, :admin)
|
136
|
+
|
137
|
+
# Check if user includes global role
|
138
|
+
Permissions.includes_role?(user, :admin)
|
139
|
+
|
140
|
+
# Check if user includes scoped role
|
141
|
+
project = Project.first
|
142
|
+
Permissions.includes_role?(user, :manager, scoped: project)
|
135
143
|
```
|
136
144
|
|
137
145
|
### Permissions
|
@@ -169,6 +177,45 @@ Ez::Permissions::API::Authrozation::NotAuthorized
|
|
169
177
|
# if you don't want raise exception, just use
|
170
178
|
Permissions.authorize(user, :create, :users) { puts 'Yeahh!' } #=> false
|
171
179
|
# Because user has scoped role in the project and don't has global role.
|
180
|
+
|
181
|
+
# and for simple cases you can always ask if user can something
|
182
|
+
Permissions.can?(user, :create, :users) => # true
|
183
|
+
Permissions.can?(user, :create, :users, scoped: project) => # false
|
184
|
+
```
|
185
|
+
|
186
|
+
### Testing
|
187
|
+
EzPermissions ships with bunch of RSpec helper methods that helps mock permission.
|
188
|
+
For large test suite (more than 5000 specs) it saves up to 30% of test runs time.
|
189
|
+
|
190
|
+
Add test helpers tou your rspec config
|
191
|
+
```ruby
|
192
|
+
require 'ez/permissions/rspec_helpers'
|
193
|
+
|
194
|
+
RSpec.configure do |config|
|
195
|
+
config.include Ez::Permissions::RSpecHelpers
|
196
|
+
end
|
197
|
+
|
198
|
+
```
|
199
|
+
|
200
|
+
Examples:
|
201
|
+
```ruby
|
202
|
+
user = User.first
|
203
|
+
project = Project.first
|
204
|
+
|
205
|
+
# Mock role, model role, all permissions and user assigned role. DB will not be touched.
|
206
|
+
assume_user_permissions(user, :admin, :all)
|
207
|
+
|
208
|
+
# In case when you need real records data to be stored in DB, use
|
209
|
+
seed_user_permissions(user, :admin, :create, :update, :users, scoped: project)
|
210
|
+
|
211
|
+
# Mock role and who possible could has or not this role
|
212
|
+
mock_role(:manager, has: [user], has_not: [User.second], scoped: project)
|
213
|
+
|
214
|
+
# Mock model (user) role assignment
|
215
|
+
mock_model_role(:worker, user)
|
216
|
+
|
217
|
+
# Mock permissions for resources/action
|
218
|
+
mock_permission(:users, :create)
|
172
219
|
```
|
173
220
|
|
174
221
|
### Kepp it excplicit!
|
@@ -13,7 +13,7 @@ module Ez
|
|
13
13
|
def authorize(model, *actions, resource, scoped: nil, raise_exception: false)
|
14
14
|
return handle_no_permission_model_callback.call(self) if handle_no_permission_model_callback && !model
|
15
15
|
|
16
|
-
return yield if
|
16
|
+
return yield if can?(model, *actions, resource, scoped: scoped)
|
17
17
|
|
18
18
|
return handle_not_authorized_callback.call(self) if handle_not_authorized_callback
|
19
19
|
|
@@ -22,12 +22,16 @@ module Ez
|
|
22
22
|
false
|
23
23
|
end
|
24
24
|
|
25
|
+
def can?(model, *actions, resource, scoped: nil)
|
26
|
+
permissions(model, *actions, resource, scoped: scoped).any?
|
27
|
+
end
|
28
|
+
|
25
29
|
private
|
26
30
|
|
27
31
|
def permissions(model, *actions, resource, scoped: nil)
|
28
32
|
# TODO: Refactor to 1 query with joins
|
29
|
-
|
30
|
-
permission_ids = Ez::Permissions::PermissionRole.where(role_id:
|
33
|
+
role_ids = model.assigned_roles.where(scoped: scoped).pluck(:role_id)
|
34
|
+
permission_ids = Ez::Permissions::PermissionRole.where(role_id: role_ids).pluck(:permission_id)
|
31
35
|
|
32
36
|
Ez::Permissions::Permission.where(
|
33
37
|
id: permission_ids,
|
@@ -17,11 +17,23 @@ module Ez
|
|
17
17
|
def reject_role(model, role_name, scoped: nil)
|
18
18
|
role = Ez::Permissions::API.get_role!(role_name)
|
19
19
|
|
20
|
+
model_role(role, model, scoped)&.delete
|
21
|
+
end
|
22
|
+
|
23
|
+
def includes_role?(model, role_name, scoped: nil)
|
24
|
+
role = Ez::Permissions::API.get_role!(role_name)
|
25
|
+
|
26
|
+
model_role(role, model, scoped) ? true : false
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def model_role(role, model, scoped)
|
20
32
|
Ez::Permissions::ModelRole.find_by(
|
21
33
|
role: role,
|
22
34
|
model: model,
|
23
35
|
scoped: scoped
|
24
|
-
)
|
36
|
+
)
|
25
37
|
end
|
26
38
|
end
|
27
39
|
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# rubocop:disable all
|
4
|
+
module Ez
|
5
|
+
module Permissions
|
6
|
+
module RSpecHelpers
|
7
|
+
def seed_user_permissions(user, role, *actions, resource, scoped: nil)
|
8
|
+
Ez::Permissions::API.create_role(role)
|
9
|
+
|
10
|
+
actions.each do |action|
|
11
|
+
Ez::Permissions::API.grant_permission(role, action, resource)
|
12
|
+
end
|
13
|
+
|
14
|
+
Ez::Permissions::API.assign_role(user, role, scoped: scoped)
|
15
|
+
end
|
16
|
+
|
17
|
+
def assume_user_permissions(model, role, *actions, resource, scoped: nil)
|
18
|
+
# ROLE
|
19
|
+
mocked_role = mock_role(role) # ROLE
|
20
|
+
|
21
|
+
# MODEL ROLE
|
22
|
+
allow(Ez::Permissions::ModelRole).to receive(:find_by).with(
|
23
|
+
role: mocked_role,
|
24
|
+
model: model,
|
25
|
+
scoped: scoped
|
26
|
+
).and_return(mock_model_role(mocked_role, model, scoped: scoped))
|
27
|
+
|
28
|
+
# PERMISSIONS
|
29
|
+
mocked_permissions = actions.map { |action| mock_permission(resource, action) }
|
30
|
+
|
31
|
+
# USER ROLES
|
32
|
+
mocked_assiges_roles = double(:mocked_assiges_roles, where: [], size: 1, first: mocked_role)
|
33
|
+
mocked_roles = double(:mocked_roles, pluck: [])
|
34
|
+
|
35
|
+
# USER PERMISSION MODEL
|
36
|
+
allow(model).to receive(:assigned_roles).and_return(mocked_assiges_roles)
|
37
|
+
allow(mocked_assiges_roles).to receive(:where).with(scoped: scoped).and_return(mocked_roles)
|
38
|
+
allow(mocked_roles).to receive(:pluck).with(:role_id).and_return [mocked_role.id]
|
39
|
+
|
40
|
+
mocked_permission_role = double(:mocked_permission_role, pluck: [])
|
41
|
+
allow(Ez::Permissions::PermissionRole).to receive(:where).with(role_id: [mocked_role.id]).and_return(mocked_permission_role)
|
42
|
+
allow(mocked_permission_role).to receive(:pluck).with(:permission_id).and_return(mocked_permissions.map(&:id))
|
43
|
+
|
44
|
+
# USER PERMISSION MODEL for scoped access
|
45
|
+
mocked_empty_permission_role = double(:mocked_permission_role, pluck: [])
|
46
|
+
allow(Ez::Permissions::PermissionRole).to receive(:where).with(role_id: []).and_return(mocked_empty_permission_role)
|
47
|
+
allow(mocked_empty_permission_role).to receive(:pluck).with(:permission_id).and_return([])
|
48
|
+
|
49
|
+
# PERMISSIONS
|
50
|
+
allow(Ez::Permissions::Permission).to receive(:where).with(
|
51
|
+
id: mocked_permissions.map(&:id),
|
52
|
+
resource: resource,
|
53
|
+
action: actions.map(&:to_s)
|
54
|
+
).and_return(mocked_permissions)
|
55
|
+
|
56
|
+
# PERMISSIONS missing for all other actions
|
57
|
+
other_resource_actions = Ez::Permissions::DSL.resource(resource).actions.reject { |a| actions.include?(a) }.map(&:to_s)
|
58
|
+
|
59
|
+
allow(Ez::Permissions::Permission).to receive(:where).with(
|
60
|
+
id: mocked_permissions.map(&:id),
|
61
|
+
resource: resource,
|
62
|
+
action: other_resource_actions
|
63
|
+
).and_return([])
|
64
|
+
|
65
|
+
# PERMISSIONS missing for scoped access
|
66
|
+
allow(Ez::Permissions::Permission).to receive(:where).with(
|
67
|
+
id: [],
|
68
|
+
resource: resource,
|
69
|
+
action: actions.map(&:to_s)
|
70
|
+
).and_return([])
|
71
|
+
end
|
72
|
+
|
73
|
+
def mock_role(name, has: [], has_not: [], scoped: nil)
|
74
|
+
mocked_role = double(:role, id: rand(1..99_999), name: name.to_s)
|
75
|
+
|
76
|
+
allow(Ez::Permissions::Role).to receive(:find_by).with(name: name).and_return(mocked_role)
|
77
|
+
allow(Ez::Permissions::Role).to receive(:find_by!).with(name: name).and_return(mocked_role)
|
78
|
+
|
79
|
+
has.each do |model|
|
80
|
+
mock_model_role(mocked_role, model, scoped: scoped)
|
81
|
+
end
|
82
|
+
|
83
|
+
has_not.each do |model|
|
84
|
+
allow(Ez::Permissions::ModelRole).to receive(:find_by).with(
|
85
|
+
role: mocked_role,
|
86
|
+
model: model,
|
87
|
+
scoped: scoped
|
88
|
+
).and_return(nil)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Allow any model to assign the role
|
92
|
+
allow(Ez::Permissions::ModelRole).to receive(:find_or_create_by!).with(
|
93
|
+
role: mocked_role,
|
94
|
+
model: anything,
|
95
|
+
scoped: scoped
|
96
|
+
).and_return(double(:mocked_model_role))
|
97
|
+
|
98
|
+
mocked_role
|
99
|
+
end
|
100
|
+
|
101
|
+
def mock_model_role(role, model, scoped: nil)
|
102
|
+
mocked_model_role = double(:mocked_model_role, role: role, model: model, scoped: scoped)
|
103
|
+
|
104
|
+
allow(Ez::Permissions::ModelRole).to receive(:find_by).with(
|
105
|
+
role: role,
|
106
|
+
model: model,
|
107
|
+
scoped: scoped
|
108
|
+
).and_return(mocked_model_role)
|
109
|
+
|
110
|
+
allow(Ez::Permissions::ModelRole).to receive(:find_or_create_by!).with(
|
111
|
+
role: role,
|
112
|
+
model: model,
|
113
|
+
scoped: scoped
|
114
|
+
).and_return(mocked_model_role)
|
115
|
+
end
|
116
|
+
|
117
|
+
def mock_permission(resource, action)
|
118
|
+
mocked_permission = double(:permission, id: rand(1..99_999), resource: resource.to_s, action: action.to_s)
|
119
|
+
|
120
|
+
allow(Ez::Permissions::Permission)
|
121
|
+
.to receive(:find_by!)
|
122
|
+
.with(resource: resource, action: action)
|
123
|
+
.and_return(mocked_permission)
|
124
|
+
|
125
|
+
mocked_permission
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
# rubocop:enable all
|
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.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Volodya Sveredyuk
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-04-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ez-core
|
@@ -178,6 +178,7 @@ files:
|
|
178
178
|
- lib/ez/permissions/engine.rb
|
179
179
|
- lib/ez/permissions/railtie.rb
|
180
180
|
- lib/ez/permissions/resource.rb
|
181
|
+
- lib/ez/permissions/rspec_helpers.rb
|
181
182
|
- lib/ez/permissions/version.rb
|
182
183
|
- lib/generators/ez/permissions/install_generator.rb
|
183
184
|
- lib/generators/ez/permissions/migrations_generator.rb
|