consent 1.0.1 → 2.1.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/.gitignore +13 -6
- data/.rubocop.yml +17 -0
- data/.rubocop_todo.yml +9 -11
- data/Appraisals +13 -0
- data/Gemfile +10 -1
- data/Gemfile.lock +259 -0
- data/Rakefile +9 -3
- data/app/models/concerns/consent/authorizable.rb +94 -0
- data/app/models/consent/application_record.rb +7 -0
- data/app/models/consent/history.rb +21 -0
- data/app/models/consent/permission.rb +71 -0
- data/bin/console +3 -3
- data/config.ru +9 -0
- data/consent.gemspec +25 -21
- data/db/migrate/20211104225614_create_nitro_auth_authorization_permissions.rb +19 -0
- data/db/migrate/20220420135558_create_nitro_auth_authorization_histories.rb +15 -0
- data/doc/dependency_decisions.yml +3 -0
- data/docs/CHANGELOG.md +32 -0
- data/docs/README.md +355 -0
- data/gemfiles/.bundle/config +2 -0
- data/gemfiles/rails_6_1.gemfile +15 -0
- data/gemfiles/rails_6_1.gemfile.lock +287 -0
- data/gemfiles/rails_7_0.gemfile +15 -0
- data/gemfiles/rails_7_0.gemfile.lock +286 -0
- data/gemfiles/rails_7_1.gemfile +15 -0
- data/gemfiles/rails_7_1.gemfile.lock +337 -0
- data/lib/consent/ability.rb +113 -4
- data/lib/consent/dsl.rb +1 -8
- data/lib/consent/{railtie.rb → engine.rb} +11 -8
- data/lib/consent/model_additions.rb +64 -0
- data/lib/consent/permission_migration.rb +139 -0
- data/lib/consent/reloader.rb +6 -5
- data/lib/consent/rspec/consent_action.rb +7 -7
- data/lib/consent/rspec/consent_view.rb +10 -14
- data/lib/consent/rspec.rb +3 -3
- data/lib/consent/subject_coder.rb +39 -0
- data/lib/consent/symbol_adapter.rb +18 -0
- data/lib/consent/version.rb +1 -1
- data/lib/consent.rb +25 -13
- data/lib/generators/consent/permissions_generator.rb +5 -5
- data/mkdocs.yml +6 -0
- data/renovate.json +15 -2
- metadata +126 -37
- data/.rspec +0 -2
- data/.ruby-version +0 -1
- data/.travis.yml +0 -20
- data/LICENSE +0 -21
- data/README.md +0 -252
- data/TODO.md +0 -1
@@ -0,0 +1,337 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ../../rubocop-powerhome
|
3
|
+
specs:
|
4
|
+
rubocop-powerhome (0.5.3)
|
5
|
+
rubocop (= 1.66.1)
|
6
|
+
rubocop-performance
|
7
|
+
rubocop-rails
|
8
|
+
rubocop-rake
|
9
|
+
rubocop-rspec
|
10
|
+
|
11
|
+
PATH
|
12
|
+
remote: ..
|
13
|
+
specs:
|
14
|
+
consent (2.1.0)
|
15
|
+
cancancan (= 3.2.1)
|
16
|
+
|
17
|
+
GEM
|
18
|
+
remote: https://rubygems.org/
|
19
|
+
specs:
|
20
|
+
actioncable (7.1.3.2)
|
21
|
+
actionpack (= 7.1.3.2)
|
22
|
+
activesupport (= 7.1.3.2)
|
23
|
+
nio4r (~> 2.0)
|
24
|
+
websocket-driver (>= 0.6.1)
|
25
|
+
zeitwerk (~> 2.6)
|
26
|
+
actionmailbox (7.1.3.2)
|
27
|
+
actionpack (= 7.1.3.2)
|
28
|
+
activejob (= 7.1.3.2)
|
29
|
+
activerecord (= 7.1.3.2)
|
30
|
+
activestorage (= 7.1.3.2)
|
31
|
+
activesupport (= 7.1.3.2)
|
32
|
+
mail (>= 2.7.1)
|
33
|
+
net-imap
|
34
|
+
net-pop
|
35
|
+
net-smtp
|
36
|
+
actionmailer (7.1.3.2)
|
37
|
+
actionpack (= 7.1.3.2)
|
38
|
+
actionview (= 7.1.3.2)
|
39
|
+
activejob (= 7.1.3.2)
|
40
|
+
activesupport (= 7.1.3.2)
|
41
|
+
mail (~> 2.5, >= 2.5.4)
|
42
|
+
net-imap
|
43
|
+
net-pop
|
44
|
+
net-smtp
|
45
|
+
rails-dom-testing (~> 2.2)
|
46
|
+
actionpack (7.1.3.2)
|
47
|
+
actionview (= 7.1.3.2)
|
48
|
+
activesupport (= 7.1.3.2)
|
49
|
+
nokogiri (>= 1.8.5)
|
50
|
+
racc
|
51
|
+
rack (>= 2.2.4)
|
52
|
+
rack-session (>= 1.0.1)
|
53
|
+
rack-test (>= 0.6.3)
|
54
|
+
rails-dom-testing (~> 2.2)
|
55
|
+
rails-html-sanitizer (~> 1.6)
|
56
|
+
actiontext (7.1.3.2)
|
57
|
+
actionpack (= 7.1.3.2)
|
58
|
+
activerecord (= 7.1.3.2)
|
59
|
+
activestorage (= 7.1.3.2)
|
60
|
+
activesupport (= 7.1.3.2)
|
61
|
+
globalid (>= 0.6.0)
|
62
|
+
nokogiri (>= 1.8.5)
|
63
|
+
actionview (7.1.3.2)
|
64
|
+
activesupport (= 7.1.3.2)
|
65
|
+
builder (~> 3.1)
|
66
|
+
erubi (~> 1.11)
|
67
|
+
rails-dom-testing (~> 2.2)
|
68
|
+
rails-html-sanitizer (~> 1.6)
|
69
|
+
activejob (7.1.3.2)
|
70
|
+
activesupport (= 7.1.3.2)
|
71
|
+
globalid (>= 0.3.6)
|
72
|
+
activemodel (7.1.3.2)
|
73
|
+
activesupport (= 7.1.3.2)
|
74
|
+
activerecord (7.1.3.2)
|
75
|
+
activemodel (= 7.1.3.2)
|
76
|
+
activesupport (= 7.1.3.2)
|
77
|
+
timeout (>= 0.4.0)
|
78
|
+
activestorage (7.1.3.2)
|
79
|
+
actionpack (= 7.1.3.2)
|
80
|
+
activejob (= 7.1.3.2)
|
81
|
+
activerecord (= 7.1.3.2)
|
82
|
+
activesupport (= 7.1.3.2)
|
83
|
+
marcel (~> 1.0)
|
84
|
+
activesupport (7.1.3.2)
|
85
|
+
base64
|
86
|
+
bigdecimal
|
87
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
88
|
+
connection_pool (>= 2.2.5)
|
89
|
+
drb
|
90
|
+
i18n (>= 1.6, < 2)
|
91
|
+
minitest (>= 5.1)
|
92
|
+
mutex_m
|
93
|
+
tzinfo (~> 2.0)
|
94
|
+
appraisal (2.5.0)
|
95
|
+
bundler
|
96
|
+
rake
|
97
|
+
thor (>= 0.14.0)
|
98
|
+
ast (2.4.2)
|
99
|
+
base64 (0.2.0)
|
100
|
+
bigdecimal (3.1.9)
|
101
|
+
builder (3.3.0)
|
102
|
+
byebug (11.1.3)
|
103
|
+
cancancan (3.2.1)
|
104
|
+
coderay (1.1.3)
|
105
|
+
combustion (1.5.0)
|
106
|
+
activesupport (>= 3.0.0)
|
107
|
+
railties (>= 3.0.0)
|
108
|
+
thor (>= 0.14.6)
|
109
|
+
concurrent-ruby (1.3.5)
|
110
|
+
connection_pool (2.5.0)
|
111
|
+
crass (1.0.6)
|
112
|
+
csv (3.3.2)
|
113
|
+
date (3.4.1)
|
114
|
+
diff-lcs (1.6.0)
|
115
|
+
drb (2.2.1)
|
116
|
+
erubi (1.13.1)
|
117
|
+
globalid (1.2.1)
|
118
|
+
activesupport (>= 6.1)
|
119
|
+
i18n (1.14.7)
|
120
|
+
concurrent-ruby (~> 1.0)
|
121
|
+
io-console (0.8.0)
|
122
|
+
irb (1.15.1)
|
123
|
+
pp (>= 0.6.0)
|
124
|
+
rdoc (>= 4.0.0)
|
125
|
+
reline (>= 0.4.2)
|
126
|
+
json (2.10.1)
|
127
|
+
language_server-protocol (3.17.0.4)
|
128
|
+
license_finder (7.2.1)
|
129
|
+
bundler
|
130
|
+
csv (~> 3.2)
|
131
|
+
rubyzip (>= 1, < 3)
|
132
|
+
thor (~> 1.2)
|
133
|
+
tomlrb (>= 1.3, < 2.1)
|
134
|
+
with_env (= 1.1.0)
|
135
|
+
xml-simple (~> 1.1.9)
|
136
|
+
logger (1.6.6)
|
137
|
+
loofah (2.24.0)
|
138
|
+
crass (~> 1.0.2)
|
139
|
+
nokogiri (>= 1.12.0)
|
140
|
+
mail (2.8.1)
|
141
|
+
mini_mime (>= 0.1.1)
|
142
|
+
net-imap
|
143
|
+
net-pop
|
144
|
+
net-smtp
|
145
|
+
marcel (1.0.4)
|
146
|
+
method_source (1.1.0)
|
147
|
+
mini_mime (1.1.5)
|
148
|
+
minitest (5.25.4)
|
149
|
+
mutex_m (0.3.0)
|
150
|
+
net-imap (0.4.19)
|
151
|
+
date
|
152
|
+
net-protocol
|
153
|
+
net-pop (0.1.2)
|
154
|
+
net-protocol
|
155
|
+
net-protocol (0.2.2)
|
156
|
+
timeout
|
157
|
+
net-smtp (0.5.1)
|
158
|
+
net-protocol
|
159
|
+
nio4r (2.7.4)
|
160
|
+
nokogiri (1.17.2-aarch64-linux)
|
161
|
+
racc (~> 1.4)
|
162
|
+
nokogiri (1.17.2-arm-linux)
|
163
|
+
racc (~> 1.4)
|
164
|
+
nokogiri (1.17.2-arm64-darwin)
|
165
|
+
racc (~> 1.4)
|
166
|
+
nokogiri (1.17.2-x86_64-darwin)
|
167
|
+
racc (~> 1.4)
|
168
|
+
nokogiri (1.17.2-x86_64-linux)
|
169
|
+
racc (~> 1.4)
|
170
|
+
parallel (1.26.3)
|
171
|
+
parser (3.3.7.1)
|
172
|
+
ast (~> 2.4.1)
|
173
|
+
racc
|
174
|
+
pp (0.6.2)
|
175
|
+
prettyprint
|
176
|
+
prettyprint (0.2.0)
|
177
|
+
pry (0.14.2)
|
178
|
+
coderay (~> 1.1)
|
179
|
+
method_source (~> 1.0)
|
180
|
+
pry-byebug (3.10.1)
|
181
|
+
byebug (~> 11.0)
|
182
|
+
pry (>= 0.13, < 0.15)
|
183
|
+
psych (5.2.3)
|
184
|
+
date
|
185
|
+
stringio
|
186
|
+
racc (1.8.1)
|
187
|
+
rack (3.1.10)
|
188
|
+
rack-session (2.1.0)
|
189
|
+
base64 (>= 0.1.0)
|
190
|
+
rack (>= 3.0.0)
|
191
|
+
rack-test (2.2.0)
|
192
|
+
rack (>= 1.3)
|
193
|
+
rackup (2.2.1)
|
194
|
+
rack (>= 3)
|
195
|
+
rails (7.1.3.2)
|
196
|
+
actioncable (= 7.1.3.2)
|
197
|
+
actionmailbox (= 7.1.3.2)
|
198
|
+
actionmailer (= 7.1.3.2)
|
199
|
+
actionpack (= 7.1.3.2)
|
200
|
+
actiontext (= 7.1.3.2)
|
201
|
+
actionview (= 7.1.3.2)
|
202
|
+
activejob (= 7.1.3.2)
|
203
|
+
activemodel (= 7.1.3.2)
|
204
|
+
activerecord (= 7.1.3.2)
|
205
|
+
activestorage (= 7.1.3.2)
|
206
|
+
activesupport (= 7.1.3.2)
|
207
|
+
bundler (>= 1.15.0)
|
208
|
+
railties (= 7.1.3.2)
|
209
|
+
rails-dom-testing (2.2.0)
|
210
|
+
activesupport (>= 5.0.0)
|
211
|
+
minitest
|
212
|
+
nokogiri (>= 1.6)
|
213
|
+
rails-html-sanitizer (1.6.2)
|
214
|
+
loofah (~> 2.21)
|
215
|
+
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
|
216
|
+
railties (7.1.3.2)
|
217
|
+
actionpack (= 7.1.3.2)
|
218
|
+
activesupport (= 7.1.3.2)
|
219
|
+
irb
|
220
|
+
rackup (>= 1.0.0)
|
221
|
+
rake (>= 12.2)
|
222
|
+
thor (~> 1.0, >= 1.2.2)
|
223
|
+
zeitwerk (~> 2.6)
|
224
|
+
rainbow (3.1.1)
|
225
|
+
rake (13.2.1)
|
226
|
+
rdoc (6.12.0)
|
227
|
+
psych (>= 4.0.0)
|
228
|
+
regexp_parser (2.10.0)
|
229
|
+
reline (0.6.0)
|
230
|
+
io-console (~> 0.5)
|
231
|
+
rexml (3.4.1)
|
232
|
+
rspec (3.13.0)
|
233
|
+
rspec-core (~> 3.13.0)
|
234
|
+
rspec-expectations (~> 3.13.0)
|
235
|
+
rspec-mocks (~> 3.13.0)
|
236
|
+
rspec-core (3.13.3)
|
237
|
+
rspec-support (~> 3.13.0)
|
238
|
+
rspec-expectations (3.13.3)
|
239
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
240
|
+
rspec-support (~> 3.13.0)
|
241
|
+
rspec-mocks (3.13.2)
|
242
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
243
|
+
rspec-support (~> 3.13.0)
|
244
|
+
rspec-rails (6.1.5)
|
245
|
+
actionpack (>= 6.1)
|
246
|
+
activesupport (>= 6.1)
|
247
|
+
railties (>= 6.1)
|
248
|
+
rspec-core (~> 3.13)
|
249
|
+
rspec-expectations (~> 3.13)
|
250
|
+
rspec-mocks (~> 3.13)
|
251
|
+
rspec-support (~> 3.13)
|
252
|
+
rspec-support (3.13.2)
|
253
|
+
rubocop (1.66.1)
|
254
|
+
json (~> 2.3)
|
255
|
+
language_server-protocol (>= 3.17.0)
|
256
|
+
parallel (~> 1.10)
|
257
|
+
parser (>= 3.3.0.2)
|
258
|
+
rainbow (>= 2.2.2, < 4.0)
|
259
|
+
regexp_parser (>= 2.4, < 3.0)
|
260
|
+
rubocop-ast (>= 1.32.2, < 2.0)
|
261
|
+
ruby-progressbar (~> 1.7)
|
262
|
+
unicode-display_width (>= 2.4.0, < 3.0)
|
263
|
+
rubocop-ast (1.38.0)
|
264
|
+
parser (>= 3.3.1.0)
|
265
|
+
rubocop-performance (1.23.1)
|
266
|
+
rubocop (>= 1.48.1, < 2.0)
|
267
|
+
rubocop-ast (>= 1.31.1, < 2.0)
|
268
|
+
rubocop-rails (2.29.1)
|
269
|
+
activesupport (>= 4.2.0)
|
270
|
+
rack (>= 1.1)
|
271
|
+
rubocop (>= 1.52.0, < 2.0)
|
272
|
+
rubocop-ast (>= 1.31.1, < 2.0)
|
273
|
+
rubocop-rake (0.6.0)
|
274
|
+
rubocop (~> 1.0)
|
275
|
+
rubocop-rspec (3.4.0)
|
276
|
+
rubocop (~> 1.61)
|
277
|
+
ruby-progressbar (1.13.0)
|
278
|
+
rubyzip (2.4.1)
|
279
|
+
sqlite3 (1.7.3-aarch64-linux)
|
280
|
+
sqlite3 (1.7.3-arm-linux)
|
281
|
+
sqlite3 (1.7.3-arm64-darwin)
|
282
|
+
sqlite3 (1.7.3-x86_64-darwin)
|
283
|
+
sqlite3 (1.7.3-x86_64-linux)
|
284
|
+
stringio (3.1.3)
|
285
|
+
thor (1.3.2)
|
286
|
+
timeout (0.4.3)
|
287
|
+
tomlrb (2.0.3)
|
288
|
+
tzinfo (2.0.6)
|
289
|
+
concurrent-ruby (~> 1.0)
|
290
|
+
unicode-display_width (2.6.0)
|
291
|
+
websocket-driver (0.7.7)
|
292
|
+
base64
|
293
|
+
websocket-extensions (>= 0.1.0)
|
294
|
+
websocket-extensions (0.1.5)
|
295
|
+
with_env (1.1.0)
|
296
|
+
xml-simple (1.1.9)
|
297
|
+
rexml
|
298
|
+
zeitwerk (2.6.18)
|
299
|
+
|
300
|
+
PLATFORMS
|
301
|
+
aarch64-linux
|
302
|
+
aarch64-linux-gnu
|
303
|
+
aarch64-linux-musl
|
304
|
+
arm-linux
|
305
|
+
arm-linux-gnu
|
306
|
+
arm-linux-musl
|
307
|
+
arm64-darwin
|
308
|
+
x86_64-darwin
|
309
|
+
x86_64-linux
|
310
|
+
x86_64-linux-gnu
|
311
|
+
x86_64-linux-musl
|
312
|
+
|
313
|
+
DEPENDENCIES
|
314
|
+
activerecord (>= 5)
|
315
|
+
appraisal (~> 2.5.0)
|
316
|
+
base64
|
317
|
+
bigdecimal
|
318
|
+
bundler (~> 2.1)
|
319
|
+
combustion (~> 1.3)
|
320
|
+
consent!
|
321
|
+
license_finder (>= 7.0)
|
322
|
+
logger
|
323
|
+
mutex_m
|
324
|
+
net-imap (< 0.5.0)
|
325
|
+
nokogiri (< 1.18)
|
326
|
+
pry (>= 0.14.2)
|
327
|
+
pry-byebug (= 3.10.1)
|
328
|
+
rails (= 7.1.3.2)
|
329
|
+
rake (~> 13)
|
330
|
+
rspec (~> 3.0)
|
331
|
+
rspec-rails (~> 6.1.5)
|
332
|
+
rubocop-powerhome!
|
333
|
+
sqlite3 (~> 1.7.3)
|
334
|
+
zeitwerk (< 2.7.0)
|
335
|
+
|
336
|
+
BUNDLED WITH
|
337
|
+
2.5.23
|
data/lib/consent/ability.rb
CHANGED
@@ -1,15 +1,64 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Consent
|
4
|
-
#
|
4
|
+
#
|
5
|
+
# Defines a CanCan(Can)::Ability class based on Consent::Permissions
|
6
|
+
#
|
5
7
|
class Ability
|
6
8
|
include CanCan::Ability
|
7
9
|
|
8
|
-
|
9
|
-
|
10
|
+
#
|
11
|
+
# Initialize a Consent::Ability consenting all the given permissions.
|
12
|
+
#
|
13
|
+
# When super_user is set to true, it grants `:manage :all`, which is understood by
|
14
|
+
# CanCan as a keyword to allow everything with no restrictions.
|
15
|
+
#
|
16
|
+
# If apply_defaults is set to true, Consent::Ability will grant the default views
|
17
|
+
# defined in the permissions.
|
18
|
+
#
|
19
|
+
# I.e.:
|
20
|
+
#
|
21
|
+
# Consent.define Project, 'Projects' do
|
22
|
+
# view :department, "User's department only" do |user|
|
23
|
+
# { department_id: user.id }
|
24
|
+
# end
|
25
|
+
# view :self, "User's own projects" do |user|
|
26
|
+
# { user_id: user.id }
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# action :close, views: %i[department self], default_view: :self
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# Consent::Ability.new(user, permissions: user&.permissions,
|
33
|
+
# super_user: user&.super_user?,
|
34
|
+
# apply_defaults: user.present?)
|
35
|
+
#
|
36
|
+
# @param [*] *context the view context, usually the user and some additional information
|
37
|
+
# @param [Array<Consent::Permission>] permissions the list of permissions to grant
|
38
|
+
# @param [Boolean] super_user whether Consent should grant :manage :all
|
39
|
+
# @param [Boolean] apply_defaults whether Consent should grant default views
|
40
|
+
#
|
41
|
+
def initialize(*context, permissions: nil, super_user: false, apply_defaults: true)
|
42
|
+
@context = *context
|
43
|
+
|
10
44
|
apply_defaults! if apply_defaults
|
45
|
+
can :manage, :all if super_user
|
46
|
+
|
47
|
+
permissions&.each do |permission|
|
48
|
+
consent(**permission.slice(:subject, :action, :view).symbolize_keys)
|
49
|
+
end
|
11
50
|
end
|
12
51
|
|
52
|
+
# Consents a subject/action/view to the ability
|
53
|
+
#
|
54
|
+
# `consent!` will add a `can` permission to the ability based on the
|
55
|
+
# view rules defined in the Consent definitions.
|
56
|
+
#
|
57
|
+
# @param [Class,Symbol] subject the target subject of the action
|
58
|
+
# @param [Symbol] action the action being granted on the subject
|
59
|
+
# @param [Symbol,nil] view the conditions/rules on which the action is granted
|
60
|
+
# @raises Consent::ViewNotFound when the view key doesn't exist in the context
|
61
|
+
#
|
13
62
|
def consent!(subject: nil, action: nil, view: nil)
|
14
63
|
view = case view
|
15
64
|
when Consent::View
|
@@ -24,13 +73,55 @@ module Consent
|
|
24
73
|
)
|
25
74
|
end
|
26
75
|
|
76
|
+
# Consents a subject/action/view to the ability
|
77
|
+
#
|
78
|
+
# @see ::Consent::Ability#consent
|
79
|
+
#
|
27
80
|
def consent(**kwargs)
|
28
81
|
consent!(**kwargs)
|
29
82
|
rescue Consent::ViewNotFound
|
30
83
|
nil
|
31
84
|
end
|
32
85
|
|
33
|
-
|
86
|
+
# Returns a hash where the keys are the given permissions, and the values
|
87
|
+
# are either true or false, representing their ability to perform the given
|
88
|
+
# permision
|
89
|
+
#
|
90
|
+
# @param [Array<String>,String,nil] permissions an array of the requested permissions
|
91
|
+
# @return [Hash<String,Boolean>] the hash with the results
|
92
|
+
def to_h(permissions = nil)
|
93
|
+
Array(permissions).reduce({}) do |result, permission|
|
94
|
+
result.merge permission => can?(permission)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Check if the user has permission to perform a given action on an object.
|
99
|
+
#
|
100
|
+
# can? :destroy, @project
|
101
|
+
#
|
102
|
+
# You can also pass the class instead of an instance (if you don't have one handy).
|
103
|
+
#
|
104
|
+
# can? :create, Project
|
105
|
+
#
|
106
|
+
# You can also check with string form of the permission:
|
107
|
+
#
|
108
|
+
# can? "project/create"
|
109
|
+
#
|
110
|
+
# For more info, check the documentation of [CanCan::Ability]
|
111
|
+
def can?(action_or_pair, subject = nil, *args)
|
112
|
+
action, subject = extract_action_subject(action_or_pair, subject)
|
113
|
+
super(action, subject, *args)
|
114
|
+
end
|
115
|
+
|
116
|
+
# @private
|
117
|
+
def relation_model_adapter(model_class, action_or_pair, subject, relation)
|
118
|
+
action, subject = extract_action_subject(action_or_pair, subject)
|
119
|
+
::CanCan::ModelAdapters::AbstractAdapter
|
120
|
+
.adapter_class(model_class)
|
121
|
+
.new(model_class, relation_rules(model_class, action, subject, relation))
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
34
125
|
|
35
126
|
def apply_defaults!
|
36
127
|
Consent.subjects.each do |subject|
|
@@ -45,5 +136,23 @@ module Consent
|
|
45
136
|
end
|
46
137
|
end
|
47
138
|
end
|
139
|
+
|
140
|
+
def relation_rules(model_class, action, subject, relation)
|
141
|
+
relevant_rules(action, subject).map do |rule|
|
142
|
+
unless rule.conditions.is_a?(Hash)
|
143
|
+
raise ::CanCan::Error, "accessible_through is only available with hash conditions"
|
144
|
+
end
|
145
|
+
|
146
|
+
conditions = rule.conditions.dig(*Array(relation))
|
147
|
+
::CanCan::Rule.new(rule.base_behavior, action, model_class, conditions, rule.block)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def extract_action_subject(action_or_string_pair, subject)
|
152
|
+
return action_or_string_pair, subject if subject
|
153
|
+
|
154
|
+
subject_key, _, action_key = action_or_string_pair.rpartition("/")
|
155
|
+
[action_key.to_sym, Consent::SubjectCoder.load(subject_key)]
|
156
|
+
end
|
48
157
|
end
|
49
158
|
end
|
data/lib/consent/dsl.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Consent
|
4
|
+
# @private
|
4
5
|
class DSL # :nodoc:
|
5
6
|
attr_reader :subject
|
6
7
|
|
@@ -13,14 +14,6 @@ module Consent
|
|
13
14
|
DSL.build(@subject, @defaults.merge(new_defaults), &block)
|
14
15
|
end
|
15
16
|
|
16
|
-
# rubocop:disable Lint/UnusedBlockArgument, Security/Eval
|
17
|
-
def eval_view(key, label, collection_conditions)
|
18
|
-
view key, label do |user|
|
19
|
-
eval(collection_conditions)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
# rubocop:enable Lint/UnusedBlockArgument, Security/Eval
|
23
|
-
|
24
17
|
def view(key, label, instance = nil, collection = nil, &block)
|
25
18
|
collection ||= block
|
26
19
|
@subject.views[key] = View.new(key, label, instance, collection)
|
@@ -1,26 +1,29 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "consent"
|
4
4
|
|
5
5
|
module Consent
|
6
6
|
# Plugs consent permission load to the Rails class loading cycle
|
7
|
-
class
|
7
|
+
class Engine < Rails::Engine
|
8
8
|
config.before_configuration do |app|
|
9
|
-
default_path = app.root.join(
|
10
|
-
config.consent = Consent::Reloader.new(
|
11
|
-
default_path,
|
12
|
-
ActiveSupport::Dependencies.mechanism
|
13
|
-
)
|
9
|
+
default_path = app.root.join("app", "permissions")
|
10
|
+
config.consent = Consent::Reloader.new(default_path)
|
14
11
|
end
|
15
12
|
|
16
13
|
config.after_initialize do |app|
|
17
14
|
app.config.consent.execute
|
18
15
|
end
|
19
16
|
|
20
|
-
initializer
|
17
|
+
initializer "consent.reloader" do |app|
|
21
18
|
app.reloaders << config.consent
|
22
19
|
ActiveSupport::Dependencies.autoload_paths -= config.consent.paths
|
23
20
|
config.to_prepare { app.config.consent.execute }
|
24
21
|
end
|
22
|
+
|
23
|
+
initializer "consent.accessible_through" do
|
24
|
+
ActiveSupport.on_load(:active_record) do
|
25
|
+
include Consent::ModelAdditions
|
26
|
+
end
|
27
|
+
end
|
25
28
|
end
|
26
29
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Consent
|
4
|
+
#
|
5
|
+
# Accessible Through logic
|
6
|
+
#
|
7
|
+
# This module adds the accessible_through class method to a model.
|
8
|
+
# It is included in the activerecord base classes by Consent::Engine.
|
9
|
+
#
|
10
|
+
# @see Consent::ModelAdditions::ClassMethods#accessible_through
|
11
|
+
#
|
12
|
+
module ModelAdditions
|
13
|
+
module ClassMethods
|
14
|
+
# Provides a scope within the model to find instances of the model that are accessible
|
15
|
+
# by the given ability through a given relation in the main subject
|
16
|
+
#
|
17
|
+
# I.E.:
|
18
|
+
#
|
19
|
+
# Given the following scenario
|
20
|
+
#
|
21
|
+
# class User
|
22
|
+
# belongs_to :territory
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# Consent.define User, "User permissions" do
|
26
|
+
# view :territory do |user|
|
27
|
+
# { territory: { id: user.territory_id } }
|
28
|
+
# end
|
29
|
+
# view :visible_territories do |user|
|
30
|
+
# { territory: { id: user.visible_territory_ids } }
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# action :contact, views: %i[all no_access territory visible_territories]
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# This would give you a list of territories that the given ability can
|
37
|
+
# contact their users:
|
38
|
+
#
|
39
|
+
# > user = User.new(territory_id: 13, visible_territory_ids: [2, 3, 4])
|
40
|
+
# > ability = Consent::Ability.new(user.to_session_user)
|
41
|
+
# > ability.consent view: :territory, action: :contact, subject: User
|
42
|
+
# > Territory.accessible_through(ability, :contact, User).to_sql
|
43
|
+
# => SELECT * FROM territories WHERE id = 13
|
44
|
+
# > ability.consent view: :visible_territories, action: :contact, subject: User
|
45
|
+
# > Territory.accessible_through(ability, :contact, User).to_sql
|
46
|
+
# => SELECT * FROM territories WHERE ((id = 13) OR (id IN (2, 3, 4)))
|
47
|
+
#
|
48
|
+
# @param ability [Consent::Ability] ability performing the query
|
49
|
+
# @param action_or_pair [Symbol,String] the name of the action or a subject/action pair
|
50
|
+
# @param subject [Class,Symbol,nil] the subject in which the action is, when action_or_pair is just the action
|
51
|
+
# @param relation [Symbol,Array<Symbol>] the relation or path to the relation
|
52
|
+
#
|
53
|
+
def accessible_through(ability, action_or_pair, subject = nil, relation: nil)
|
54
|
+
relation ||= model_name.element.to_sym
|
55
|
+
ability.relation_model_adapter(self, action_or_pair, subject, relation)
|
56
|
+
.database_records
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.included(base)
|
61
|
+
base.extend ClassMethods
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|