i_am_i_can 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +13 -0
  5. data/CHANGELOG.md +17 -0
  6. data/CODE_OF_CONDUCT.md +74 -0
  7. data/Gemfile +6 -0
  8. data/Gemfile.lock +116 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +442 -0
  11. data/Rakefile +6 -0
  12. data/bin/console +14 -0
  13. data/bin/setup +8 -0
  14. data/i_am_i_can.gemspec +36 -0
  15. data/lib/generators/i_am_i_can/setup_generator.rb +56 -0
  16. data/lib/generators/i_am_i_can/templates/migrations/add_to_subject.erb +5 -0
  17. data/lib/generators/i_am_i_can/templates/migrations/permission.erb +15 -0
  18. data/lib/generators/i_am_i_can/templates/migrations/role.erb +13 -0
  19. data/lib/generators/i_am_i_can/templates/migrations/role_group.erb +14 -0
  20. data/lib/generators/i_am_i_can/templates/models/permission.erb +11 -0
  21. data/lib/generators/i_am_i_can/templates/models/role.erb +10 -0
  22. data/lib/generators/i_am_i_can/templates/models/role_group.erb +11 -0
  23. data/lib/i_am_i_can/config.rb +14 -0
  24. data/lib/i_am_i_can/has_an_array_of.rb +75 -0
  25. data/lib/i_am_i_can/permission/assignment.rb +90 -0
  26. data/lib/i_am_i_can/permission/definition.rb +61 -0
  27. data/lib/i_am_i_can/permission/helpers.rb +46 -0
  28. data/lib/i_am_i_can/permission/p_array.rb +22 -0
  29. data/lib/i_am_i_can/permission.rb +68 -0
  30. data/lib/i_am_i_can/role/assignment.rb +76 -0
  31. data/lib/i_am_i_can/role/definition.rb +100 -0
  32. data/lib/i_am_i_can/role/helpers.rb +28 -0
  33. data/lib/i_am_i_can/subject/permission_querying.rb +69 -0
  34. data/lib/i_am_i_can/subject/role_querying.rb +66 -0
  35. data/lib/i_am_i_can/version.rb +3 -0
  36. data/lib/i_am_i_can.rb +61 -0
  37. metadata +220 -0
data/README.md ADDED
@@ -0,0 +1,442 @@
1
+ # IAmICan [PostgreSQL only currently]
2
+
3
+ [![Build Status](https://travis-ci.org/zhandao/i_am_i_can.svg?branch=master)](https://travis-ci.org/zhandao/i_am_i_can)
4
+ [![Maintainability](https://api.codeclimate.com/v1/badges/27b664da01b6cc7180e3/maintainability)](https://codeclimate.com/github/zhandao/i_am_i_can/maintainability)
5
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/27b664da01b6cc7180e3/test_coverage)](https://codeclimate.com/github/zhandao/i_am_i_can/test_coverage)
6
+
7
+ Concise and Natural DSL for `Subject - Role(Role Group) - Permission` Management.
8
+
9
+ ```ruby
10
+ # our Subject is People, and subject is he:
11
+ he = People.take
12
+ # let: Roles means PeopleRole, Groups means PeopleRoleGroup
13
+
14
+ # Role
15
+ People.have_role :admin # role definition
16
+ he.becomes_a :admin # role assignment
17
+ he.is? :admin # role querying => true
18
+ he.is? :someone_else # role querying => false
19
+
20
+ # Role Group
21
+ # role definition and grouping
22
+ People.have_and_group_roles :dev, :master, :committer, by_name: :team
23
+ he.becomes_a :master # role assignment
24
+ he.in_role_group? :team # role group querying => true
25
+
26
+ # Role - Permission
27
+ People.have_role :coder # role definition
28
+ Roles.have_permission :fly # permission definition
29
+ Roles.which(name: :coder).can :fly # permission assignment (by predicate)
30
+ he.becomes_a :coder # role assignment
31
+ he.can? :fly # permission querying
32
+
33
+ # Role Group - Permission
34
+ Groups.have_permission :manage, obj: User # permission definition
35
+ Groups.which(name: :team).can :manage, obj: User # permission assignment (by predicate and object)
36
+ he.is? :master # yes
37
+ he.can? :manage, User # permission querying
38
+
39
+ # more concise and faster way
40
+ he.becomes_a :magician, which_can: [:perform], obj: :magic
41
+ he.is? :magician # => true
42
+ Roles.which(name: :magician).can? :perform, :magic # => true
43
+ he.can? :perform, :magic # => true
44
+
45
+ # Cancel Assignment
46
+ he.falls_from :admin
47
+ Roles.which(name: :coder).cannot :fly
48
+ ```
49
+
50
+ ## Concepts and Overview
51
+
52
+ ### Definition and uniqueness of nouns
53
+
54
+ 1. Role
55
+ - definition: TODO
56
+ - uniqueness: by `name`
57
+ 1. Role Group
58
+ - definition: TODO
59
+ - uniqueness: by `name`
60
+ 1. Permission
61
+ - definition: TODO
62
+ - uniqueness: by `predicate + object` (name)
63
+
64
+
65
+ ### In one word:
66
+ ```
67
+ - role has permissions
68
+ - subject has the roles
69
+ > subject has the permissions through the roles.
70
+ ```
71
+
72
+ ### About role group?
73
+ ```
74
+ - role group has permissions
75
+ - roles are in the group
76
+ - subject has one or more of the roles
77
+ > subject has the permissions through the role which is in the group
78
+ ```
79
+
80
+ ### Three steps of this gem
81
+
82
+ 1. Querying
83
+ - Find if the given role is assigned to the subject
84
+ - Find if the given permission is assigned to the subject's roles / group
85
+ - instance methods, like: `user.can? :fly`
86
+ 2. Assignment
87
+ - assign role to subject, or assign permission to role / group
88
+ - instance methods, like: `user.has_role :admin`
89
+ 3. Definition
90
+ - the role or permission you want to assign **MUST** be defined before
91
+ - option :auto_define_before (before assignment) you may need in some cases
92
+ - class methods, like: `UserRoleGroup.have_permission :fly`
93
+
94
+ **Definition => Assignment => Querying**
95
+
96
+ ### Two Concepts of this gem
97
+
98
+ 1. Stored (save in database)
99
+ 2. Local (variable value)
100
+
101
+ [Feature List: needs you](https://github.com/zhandao/i_am_i_can/issues/2)
102
+
103
+ ## Installation And Setup
104
+
105
+ 1. Add this line to your application's Gemfile and then `bundle`:
106
+
107
+ ```ruby
108
+ gem 'i_am_i_can'
109
+ ```
110
+
111
+ 2. Generate migrations and models by your subject name:
112
+
113
+ ```bash
114
+ rails g i_am_i_can:setup <subject_name>
115
+ ```
116
+
117
+ For example, if your subject name is `user`, it will generate
118
+ model `UserRole`, `UserRoleGroup` and `UserPermission`
119
+
120
+ 3. run `rails db:migrate`
121
+
122
+ 4. enable it in your subject model, like:
123
+
124
+ ```ruby
125
+ class User
126
+ act_as_i_am_i_can
127
+ end
128
+ ```
129
+
130
+ [here](#options) is some options you can pass to the declaration.
131
+
132
+ That's all!
133
+
134
+ ## Usage
135
+
136
+ ### Options
137
+
138
+ TODO
139
+
140
+ ### Methods and their Aliases
141
+
142
+ #### A. [Role Definition](https://github.com/zhandao/i_am_i_can/blob/master/lib/i_am_i_can/role/definition.rb)
143
+
144
+ 1. Caller: Subject Model, like `User`
145
+ 2. methods:
146
+ 1. save to database: `have_role`. aliases:
147
+ 1. `have_roles`
148
+ 2. `has_role` & `has_roles`
149
+ 2. save to local variable: `declare_role`. alias `declare_roles`
150
+ 3. helpers:
151
+ 1. `defined_local_roles`
152
+ 2. `defined_stored_roles` & `defined_stored_role_names`
153
+ 3. `defined_roles`
154
+
155
+ Methods Explanation:
156
+ ```ruby
157
+ # === Save to DB ===
158
+ # method signature
159
+ have_role *names, desc: nil, save: default_save#, which_can: [ ], obj: nil
160
+ # examples
161
+ User.have_roles :admin, :master # => 'Role Definition Done' or error message
162
+ User.defined_stored_roles.keys.count # => 2
163
+
164
+ # === Save in Local ===
165
+ # signature as `have_role`
166
+ # examples
167
+ User.declare_role :coder # => 'Role Definition Done' or error message
168
+ User.defined_local_roles.keys.count # => 1
169
+
170
+ User.defined_roles.keys.count # => 3
171
+ ```
172
+
173
+ #### B. [Grouping Roles](https://github.com/zhandao/i_am_i_can/blob/master/lib/i_am_i_can/role/definition.rb)
174
+
175
+ **Tips:**
176
+ 1. Role Group must be saved in database currently
177
+ 2. Roles that you're going to group should be defined
178
+
179
+ Overview:
180
+ 1. Caller: Subject Model, like `User`
181
+ 2. method: `group_roles`. aliases:
182
+ 1. `group_role`
183
+ 2. `groups_role` & `groups_roles`
184
+ 3. shortcut combination method: `have_and_group_roles` (alias `has_and_groups_roles`)
185
+ it will do: roles definition => roles grouping
186
+ 4. helpers:
187
+ 1. `defined_role_groups` & `defined_role_group_names`
188
+ 2. `members_of_role_group`
189
+
190
+ Methods Explanation:
191
+ ```ruby
192
+ # method signature
193
+ group_roles *members, by_name:, #which_can: [ ], obj: nil
194
+ # examples
195
+ User.have_and_group_roles :vip1, :vip2, :vip3, by_name: :vip
196
+ User.defined_role_group_names # => [:vip]
197
+ User.members_of_role_group(:vip) # => %i[vip1 vip2 vip3]
198
+ ```
199
+
200
+ #### C. [Role Assignment](https://github.com/zhandao/i_am_i_can/blob/master/lib/i_am_i_can/role/definition.rb)
201
+
202
+ 1. Caller: subject instance, like `User.find(1)`
203
+ 2. assign methods:
204
+ 1. save to database: `becomes_a`. aliases:
205
+ 1. `is` & `is_a_role` & `is_roles`
206
+ 2. `has_role` & `has_roles`
207
+ 3. `role_is` & `role_are`
208
+ 2. save to local variable: `temporarily_is`. alias `locally_is`
209
+ 3. cancel assign method: `falls_from`. aliases:
210
+ 1. `removes_role`
211
+ 2. `leaves`
212
+ 3. `is_not_a` & `has_not_role` & `has_not_roles`
213
+ 4. `will_not_be`
214
+ 4. helpers:
215
+ 1. `local_roles` & `local_role_names`
216
+ 2. `stored_roles` & `stored_role_names`
217
+ 3. `roles`
218
+
219
+ Methods Explanation:
220
+ ```ruby
221
+ he = User.take
222
+ # === Save to DB ===
223
+ # method signature
224
+ becomes_a *roles, auto_define_before: auto_define_before, save: default_save#, which_can: [ ], obj: nil
225
+ # examples
226
+ he.becomes_a :admin # => 'Role Definition Done' or error message
227
+ he.stored_roles # => [<#UserRole id: 1>]
228
+
229
+ # === Save in Local ===
230
+ # signature as `becomes_a`
231
+ # examples
232
+ he.temporarily_is :coder # => 'Role Assignment Done' or error message
233
+ he.local_roles # => [{ coder: { .. } }]
234
+
235
+ he.roles # => [:admin, :coder]
236
+
237
+ # === Cancel ===
238
+ # method signature
239
+ falls_from *roles, saved: default_save
240
+ # examples
241
+ he.falls_from :admin # => 'Role Assignment Done' or error message
242
+ he.removes_roles :coder, saved: false # => 'Role Assignment Done' or error message
243
+ he.roles # => []
244
+ ```
245
+
246
+ #### D. [Role / Group Querying](https://github.com/zhandao/i_am_i_can/blob/master/lib/i_am_i_can/subject/role_querying.rb)
247
+
248
+ 1. Caller: subject instance, like `User.find(1)`
249
+ 2. role querying methods:
250
+ 1. `is?` / `is_role?` / `has_role?`
251
+ 2. `isnt?`
252
+ 3. `is!` / `is_role!` / `has_role!`
253
+ 4. `is_one_of?` / `is_one_of_roles?`
254
+ 4. `is_one_of!` / `is_one_of_roles!`
255
+ 5. `is_every?` / `is_every_role_in?`
256
+ 6. `is_every!` / `is_every_role_in!`
257
+ 3. group querying methods:
258
+ 1. `is_in_role_group?` / `in_role_group?`
259
+ 2. `is_in_one_of?` / `in_one_of?`
260
+
261
+ all the `?` methods will return `true` or `false`
262
+ all the `!` bang methods will return `true` or raise `IAmICan::VerificationFailed`
263
+
264
+ Methods Examples:
265
+ ```ruby
266
+ he = User.take
267
+
268
+ he.is? :admin
269
+ he.isnt? :admin
270
+ he.is! :admin
271
+
272
+ he.is_every? :admin, :master # return false if he is not a admin or master
273
+ he.is_one_of! :admin, :master # return true if he is a master or admin
274
+
275
+ he.is_in_role_group? :vip # return true if he has a role which is in the group :vip
276
+ ```
277
+
278
+ #### E. [Permission Definition](https://github.com/zhandao/i_am_i_can/blob/master/lib/i_am_i_can/permission/definition.rb)
279
+
280
+ 1. Caller: Role / Role Group Model, like `UserRole` / `UserRoleGroup`
281
+ 2. methods:
282
+ 1. save to database: `have_permission`. aliases:
283
+ 1. `have_permissions`
284
+ 2. `has_permission` & `has_permissions`
285
+ 2. save to local variable: `declare_permission`. alias `declare_permissions`
286
+ 3. helpers:
287
+ 1. `defined_local_permissions`
288
+ 2. `defined_stored_permissions`
289
+ 3. `defined_permissions`
290
+ 4. class method: `which(name:)`
291
+ 5. Permission
292
+ 1. class method: `which(pred:, obj:)`
293
+ 2. instance methods: `#pred`, `#obj`, `#name`
294
+
295
+ Methods Explanation:
296
+ ```ruby
297
+ # === Save to DB ===
298
+ # method signature
299
+ have_permission *preds, obj: nil, desc: nil, save: default_save
300
+ # examples
301
+ UserRole.have_permission :fly # => 'Permission Definition Done' or error message
302
+ UserRole.defined_stored_permissions.keys.count # => 1
303
+ UserRoleGroup.have_permissions *%i[read write], obj: Book.find(1) # => 'Permission Definition Done' or error message
304
+ UserRoleGroup.defined_stored_permissions.keys.count # => 1
305
+
306
+ # === Save in Local ===
307
+ # signature as `have_permission`
308
+ # examples
309
+ UserRole.declare_permission :perform, obj: :magic # => 'Permission Definition Done' or error message
310
+ UserRole.defined_local_permissions.keys.count # => 1
311
+
312
+ UserRole.defined_permissions.keys.count # => 2
313
+
314
+ # === class methods ===
315
+ UserRole.which(name: :admin)
316
+ # as same as
317
+ UserRole.find_by_name!(:admin)
318
+
319
+ # === Permission ===
320
+ p = UserPermission.which(pred: :read, obj: Book.find(1))
321
+ p.pred == 'read'
322
+ p.obj == Book.find(1)
323
+ p.name == :read_Book_1
324
+ ```
325
+
326
+ #### F. [Permission Assignment](https://github.com/zhandao/i_am_i_can/blob/master/lib/i_am_i_can/permission/assignment.rb)
327
+
328
+ **What is Wrong Assignment - Covered?**
329
+ > Before: he can manage User
330
+ > When you do: he can manage User.find(1)
331
+ > will get an Error, tell you that User is cover User.find(1), no need to assign
332
+
333
+ Overview:
334
+ 1. Caller: role / role group instance, like `UserRole.which(name: :admin)`
335
+ 2. methods:
336
+ 1. save to database: `can`. aliases: `has_permission`
337
+ 2. save to local variable: `temporarily_can`. alias `locally_can`
338
+ 3. cancel assign method: `cannot`. alias `is_not_allowed_to`
339
+ 3. helpers:
340
+ 1. `local_permissions`
341
+ 2. `stored_permissions`
342
+ 3. `permissions`
343
+
344
+ Methods Explanation:
345
+ ```ruby
346
+ role = UserRole.which(name: :admin)
347
+
348
+ # === Save to DB ===
349
+ # method signature
350
+ can *preds, obj: nil, strict_mode: false, auto_define_before: auto_define_before
351
+ # examples
352
+ role.can :fly # => 'Permission Assignment Done' or error message
353
+ role.stored_permissions # => [<#UserPermission id: ..>]
354
+
355
+ # === Save in Local
356
+ # signature as `can`
357
+ # examples
358
+ role.temporarily_can :perform, obj: :magic # => 'Permission Assignment Done' or error message
359
+ role.local_permissions # => [:perform_magic]
360
+
361
+ role.permissions.keys.count # => 3
362
+ ```
363
+
364
+ #### G. [Permission Querying](https://github.com/zhandao/i_am_i_can/blob/master/lib/i_am_i_can/subject/role_querying.rb)
365
+
366
+ 1. Caller:
367
+ 1. subject instance, like `User.find(1)`
368
+ 2. role / role group instance, like `Role.which(name: :master)`
369
+ notice that this caller have only `can?` and `temporarily_can?` methods.
370
+ 2. methods:
371
+ 1. `can?`
372
+ 2. `cannot?`
373
+ 3. `can!`
374
+ 4. `can_each?` & `can_each!`
375
+ 4. `can_one_of!` & `can_one_of!`
376
+ 5. `temporarily_can?` / `locally_can?`
377
+ 6. `stored_can?`
378
+ 7. `group_can?`
379
+ 3. helpers:
380
+ 1. `permissions_of_stored_roles`
381
+ 2. `permissions_of_local_roles`
382
+ 3. `permissions_of_role_groups`
383
+
384
+ all the `?` methods will return `true` or `false`
385
+ all the `!` bang methods will return `true` or raise `IAmICan::InsufficientPermission`
386
+
387
+ Methods Examples:
388
+ ```ruby
389
+ he = User.take
390
+
391
+ he.can? :perform, :magic
392
+ he.cannot? :perform, :magic
393
+ he.can! :perform, :magic
394
+
395
+ he.can_each? :fly, :jump # return false if he can not fly or jump
396
+ he.can_one_of! :fly, :jump # return true if he can fly or jump
397
+ ```
398
+
399
+ #### H. Shortcut Combinations - which_can
400
+
401
+ Faster way to assign, define roles and thier permissions.
402
+ You can use it when defining role even assigning role.
403
+
404
+ ```ruby
405
+ # === use when defining role ===
406
+ # it does:
407
+ # 1. define the role to Subject Model
408
+ # 2. define & assign the permission to the role
409
+ User.have_role :coder, which_can: [:perform], obj: :magic
410
+ UserRole.which(name: :coder).can? :perform, :magic # => true
411
+ # save in local
412
+ User.local_role_which(name: :local_role, can: [:perform], obj: :magic)
413
+ UserRole.new(name: :local_role).temporarily_can? :perform, :magic # => true
414
+
415
+ # === use when assigning role ===
416
+ # it does:
417
+ # 1. define the role to Subject Model
418
+ # 2. assign the role to subject instance
419
+ # 2. define & assign the permission to the role
420
+ user = User.take
421
+ user.becomes_a :master, which_can: [:read], obj: :book
422
+ user.is? :master # => true
423
+ user.can? :read, :book # => true
424
+ ```
425
+
426
+ ## Development
427
+
428
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
429
+
430
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
431
+
432
+ ## Contributing
433
+
434
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/i_am_i_can. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
435
+
436
+ ## License
437
+
438
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
439
+
440
+ ## Code of Conduct
441
+
442
+ Everyone interacting in the IAmICan project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/i_am_i_can/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "i_am_i_can"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,36 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "i_am_i_can/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "i_am_i_can"
8
+ spec.version = IAmICan::VERSION
9
+ spec.authors = ["zhandao"]
10
+ spec.email = ["x@skippingcat.com"]
11
+
12
+ spec.summary = 'Concise and Natural DSL for `Subject - Role(Role Group) - Permission` Management.'
13
+ spec.description = 'Concise and Natural DSL for `Subject - Role(Role Group) - Permission` Management.'
14
+ spec.homepage = 'https://github.com/zhandao/i_am_i_can'
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.16"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "rspec", "~> 3.0"
27
+ spec.add_development_dependency 'rspec-rails'
28
+ spec.add_development_dependency 'database_cleaner'
29
+ spec.add_development_dependency 'pg'
30
+ spec.add_development_dependency 'simplecov'
31
+
32
+
33
+ spec.add_dependency 'activerecord'
34
+ spec.add_dependency 'activesupport'
35
+ spec.add_dependency 'railties'
36
+ end
@@ -0,0 +1,56 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/named_base'
3
+ require 'rails/generators/migration'
4
+ require 'rails/generators/active_record'
5
+
6
+ module IAmICan
7
+ module Generators
8
+ class SetupGenerator < Rails::Generators::NamedBase
9
+ include Rails::Generators::Migration
10
+
11
+ desc 'Generates migrations and models for the subject'
12
+
13
+ source_root File.expand_path('../templates', __FILE__)
14
+
15
+ def questions
16
+ @ii_opts = { }
17
+ unless yes?('Do you want to use role group?')
18
+ @ii_opts[:without_group] = true
19
+ end
20
+ unless yes?('Do yo want it to save role and permission to database by default?')
21
+ @ii_opts[:default_save] = false
22
+ end
23
+ if yes?('Do you want it to raise error when you are doing wrong definition or assignment?')
24
+ @ii_opts[:strict_mode] = true
25
+ end
26
+ if yes?('Do you want it to define the role/permission which is not defined when assigning to subject?')
27
+ @ii_opts[:auto_define_before] = true
28
+ end
29
+ end
30
+
31
+ def setup_migrations
32
+ dest_prefix = 'db/migrate/i_am_i_can_'
33
+ migration_template 'migrations/add_to_subject.erb', "#{dest_prefix}add_role_ids_to_#{name.underscore}.rb"
34
+ migration_template 'migrations/role.erb', "#{dest_prefix}create_#{name.underscore}_roles.rb"
35
+ migration_template 'migrations/role_group.erb', "#{dest_prefix}create_#{name.underscore}_role_groups.rb" unless @ii_opts[:without_group]
36
+ migration_template 'migrations/permission.erb', "#{dest_prefix}create_#{name.underscore}_permissions.rb"
37
+ end
38
+
39
+ def setup_models
40
+ template 'models/role.erb', "app/models/#{name.underscore}_role.rb"
41
+ template 'models/role_group.erb', "app/models/#{name.underscore}_role_group.rb" unless @ii_opts[:without_group]
42
+ template 'models/permission.erb', "app/models/#{name.underscore}_permission.rb"
43
+ end
44
+
45
+ def tip
46
+ options = ' ' + @ii_opts.to_s[2..-2].gsub('=>', ': ').gsub(', :', ', ') if @ii_opts.keys.present?
47
+ puts 'Please add this line to your subject model:'.red
48
+ puts " act_as_i_am_i_can#{options}".red
49
+ end
50
+
51
+ def self.next_migration_number(dirname)
52
+ ActiveRecord::Generators::Base.next_migration_number(dirname)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,5 @@
1
+ class IAmICanAddRoleIdsTo<%= name.camelize %> < ActiveRecord::Migration::Current
2
+ def change
3
+ add_column :<%= "#{name.underscore.pluralize}" %>, :role_ids, :integer, array: true, default: [ ]
4
+ end
5
+ end
@@ -0,0 +1,15 @@
1
+ class IAmICanCreate<%= "#{name.underscore}_permissions".camelize %> < ActiveRecord::Migration::Current
2
+ def change
3
+ create_table :<%= "#{name.underscore}_permissions" %>, force: :cascade do |t|
4
+ t.string :pred, null: false
5
+ t.string :obj_type
6
+ t.integer :obj_id
7
+ t.string :desc
8
+
9
+ t.timestamps
10
+ end
11
+
12
+ add_index :<%= "#{name.underscore}_permissions" %>, %i[pred obj_type obj_id],
13
+ unique: true, name: 'permission_unique_index', using: :btree
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ class IAmICanCreate<%= "#{name.underscore}_roles".camelize %> < ActiveRecord::Migration::Current
2
+ def change
3
+ create_table :<%= "#{name.underscore}_roles" %>, force: :cascade do |t|
4
+ t.string :name, null: false
5
+ t.integer :permission_ids, array: true, default: [ ]
6
+ t.string :desc
7
+
8
+ t.timestamps
9
+ end
10
+
11
+ add_index :<%= "#{name.underscore}_roles" %>, :name, unique: true, name: 'role_unique_index', using: :btree
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ class IAmICanCreate<%= "#{name.underscore}_role_groups".camelize %> < ActiveRecord::Migration::Current
2
+ def change
3
+ create_table :<%= "#{name.underscore}_role_groups" %>, force: :cascade do |t|
4
+ t.string :name, null: false
5
+ t.integer :member_ids, array: true, default: [ ]
6
+ t.integer :permission_ids, array: true, default: [ ]
7
+ t.string :desc
8
+
9
+ t.timestamps
10
+ end
11
+
12
+ add_index :<%= "#{name.underscore}_role_groups" %>, :name, unique: true, name: 'role_group_unique_index', using: :btree
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ class <%= name.camelize %>Permission < ActiveRecord::Base
2
+ end
3
+
4
+ __END__
5
+
6
+ string :pred, null: false
7
+ string :obj_type
8
+ integer :obj_id
9
+ string :desc
10
+
11
+ index %i[pred obj_type obj_id], unique: true, name: 'permission_unique_index'
@@ -0,0 +1,10 @@
1
+ class <%= name.camelize %>Role < ActiveRecord::Base
2
+ end
3
+
4
+ __END__
5
+
6
+ string :name, null: false
7
+ integer :permission_ids, array: true, default: [ ]
8
+ string :desc
9
+
10
+ index :name, unique: true, name: 'role_unique_index'
@@ -0,0 +1,11 @@
1
+ class <%= name.camelize %>RoleGroup < ActiveRecord::Base
2
+ end
3
+
4
+ __END__
5
+
6
+ string :name, null: false
7
+ integer :member_ids, array: true, default: [ ]
8
+ integer :permission_ids, array: true, default: [ ]
9
+ string :desc
10
+
11
+ index :name, unique: true, name: 'role_group_unique_index'
@@ -0,0 +1,14 @@
1
+ module IAmICan
2
+ class Config
3
+ attr_accessor :subject_model, :role_model, :role_group_model, :permission_model,
4
+ :auto_define_before, :strict_mode, :without_group, :default_save
5
+
6
+ def initialize(**options)
7
+ self.auto_define_before = false
8
+ self.strict_mode = false
9
+ self.without_group = false
10
+ self.default_save = true
11
+ options.each { |(key, val)| self.send("#{key}=", val) }
12
+ end
13
+ end
14
+ end