i_am_i_can 3.0.1 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/README.md +236 -174
  4. data/lib/generators/i_am_i_can/setup_generator.rb +3 -7
  5. data/lib/generators/i_am_i_can/templates/migrations/i_am_i_can.erb +8 -8
  6. data/lib/generators/i_am_i_can/templates/models/permission.erb +4 -2
  7. data/lib/generators/i_am_i_can/templates/models/role.erb +3 -1
  8. data/lib/generators/i_am_i_can/templates/models/role_group.erb +3 -1
  9. data/lib/i_am_i_can/configs/config.rb +2 -3
  10. data/lib/i_am_i_can/configs/configs.rb +1 -7
  11. data/lib/i_am_i_can/helpers/dynamic.rb +102 -0
  12. data/lib/i_am_i_can/helpers/result_of.rb +71 -0
  13. data/lib/i_am_i_can/permission/assignment.rb +12 -60
  14. data/lib/i_am_i_can/permission/definition.rb +8 -28
  15. data/lib/i_am_i_can/permission.rb +18 -24
  16. data/lib/i_am_i_can/resource.rb +24 -19
  17. data/lib/i_am_i_can/role/assignment.rb +24 -45
  18. data/lib/i_am_i_can/role/definition.rb +17 -47
  19. data/lib/i_am_i_can/role.rb +14 -0
  20. data/lib/i_am_i_can/role_group/assignment.rb +6 -0
  21. data/lib/i_am_i_can/role_group/definition.rb +25 -0
  22. data/lib/i_am_i_can/subject/permission_querying.rb +28 -40
  23. data/lib/i_am_i_can/subject/role_querying.rb +8 -8
  24. data/lib/i_am_i_can/subject.rb +0 -10
  25. data/lib/i_am_i_can/support/association_class_methods.rb +43 -0
  26. data/lib/i_am_i_can/{configurable.rb → support/configurable.rb} +0 -7
  27. data/lib/i_am_i_can/support/reflection.rb +36 -0
  28. data/lib/i_am_i_can/version.rb +1 -1
  29. data/lib/i_am_i_can.rb +33 -16
  30. metadata +9 -9
  31. data/Gemfile.lock +0 -121
  32. data/lib/i_am_i_can/dynamic_generate.rb +0 -95
  33. data/lib/i_am_i_can/permission/helpers.rb +0 -75
  34. data/lib/i_am_i_can/permission/p_array.rb +0 -22
  35. data/lib/i_am_i_can/reflection.rb +0 -25
  36. data/lib/i_am_i_can/role/helpers.rb +0 -76
@@ -1,95 +0,0 @@
1
- module IAmICan
2
- module DynamicGenerate
3
- extend self
4
-
5
- def scopes
6
- # Generate scopes of each specified i_am_i_can association
7
- #
8
- # scope :with_stored_roles, -> { includes(:stored_roles) }
9
- #
10
- proc do |keys|
11
- keys.each do |k|
12
- scope :"with_#{_reflect_of(k)}", -> { includes(_reflect_of(k)) }
13
- end
14
- end
15
- end
16
-
17
- def class_reflections
18
- # Extend each associated querying to a class method that returns ActiveRecord::Relation
19
- #
20
- # Suppose: in UserRole model,
21
- # has_and_belongs_to_many :related_users
22
- #
23
- # It will do like this:
24
- # def self.related_users
25
- # i_am_i_can.subject_model.with_stored_roles.where(user_roles: { id: self.ids })
26
- # end
27
- #
28
- # Usage:
29
- # UserRole.all.related_users
30
- #
31
- proc do
32
- %w[ subject role role_group permission ].each do |k|
33
- next unless _reflect_of(k)
34
- define_singleton_method _reflect_of(k) do
35
- model = i_am_i_can.send("#{k}_model")
36
- raise NoMethodError unless (reflect_name = model._reflect_of(i_am_i_can.act))
37
- model.send("with_#{reflect_name}").where(
38
- self.name.underscore.pluralize => { id: self.ids }
39
- )
40
- end
41
- end
42
- end
43
- end
44
-
45
- def assignment_helpers
46
- # Generate 4 methods for each Content of Assignment
47
- #
48
- # Example for a subject model called User, which `has_and_belongs_to_many :stored_roles`.
49
- # You call this proc by given contents [:role], then:
50
- #
51
- # 1. stored_roles_add
52
- # Add roles to a user instance
53
- #
54
- # 2. stored_roles_add
55
- # Remove roles to a user instance
56
- #
57
- # 3. stored_role_names
58
- # Get names of stored_roles of a user instance
59
- #
60
- # 4. self.stored_role_names
61
- # Get names of stored_roles of User ActiveRecord::Relation
62
- #
63
- proc do |contents|
64
- contents.each do |content|
65
- # TODO: refactoring
66
- define_method "#{_reflect_of(content)}_add" do |locate_vals = nil, check_size: nil, **condition|
67
- condition = { name: locate_vals } if locate_vals
68
- assoc = send("_#{content.to_s.pluralize}")
69
- records = i_am_i_can.send("#{content}_model").where(condition).where.not(id: assoc.ids)
70
- # will return false if it does nothing
71
- return false if records.blank? || (check_size && records.count != check_size)
72
- assoc << records
73
- end
74
-
75
- define_method "#{_reflect_of(content)}_rmv" do |locate_vals = nil, check_size: nil, **condition|
76
- condition = { name: locate_vals } if locate_vals
77
- assoc = send("_#{content.to_s.pluralize}")
78
- records = i_am_i_can.send("#{content}_model").where(id: assoc.ids, **condition)
79
- # will return false if it does nothing
80
- return false if records.blank? || (check_size && records.count != check_size)
81
- assoc.destroy(records)
82
- end
83
-
84
- define_method "#{_reflect_of(content).to_s.singularize}_names" do
85
- send("_#{content.to_s.pluralize}").map(&:name).map(&:to_sym)
86
- end
87
-
88
- define_singleton_method "#{_reflect_of(content).to_s.singularize}_names" do
89
- all.flat_map { |user| user.send("#{_reflect_of(content).to_s.singularize}_name") }.uniq
90
- end
91
- end
92
- end
93
- end
94
- end
95
- end
@@ -1,75 +0,0 @@
1
- module IAmICan
2
- module Permission
3
- module Helpers
4
- module Cls
5
- def _pms_definition_result(preds, obj, failed_items)
6
- prefix = 'Permission Definition Done'
7
- fail_msg = prefix + ", but #{failed_items} have been defined" if failed_items.present?
8
- raise Error, fail_msg if i_am_i_can.strict_mode && fail_msg
9
- puts fail_msg || prefix unless ENV['ITEST']
10
- prefix.present?
11
- end
12
-
13
- def _to_store_permission(pred, obj, **options)
14
- return false if i_am_i_can.permission_model.exists?(pred, obj)
15
- i_am_i_can.permission_model.create!(pred: pred, **deconstruct_obj(obj), **options)
16
- end
17
-
18
- def pms_naming(pred, obj)
19
- i_am_i_can.permission_model.naming(pred, obj)
20
- end
21
-
22
- def deconstruct_obj(obj)
23
- i_am_i_can.permission_model.deconstruct_obj(obj)
24
- end
25
-
26
- def defined_local_permissions
27
- @defined_local_permissions ||= { }
28
- end
29
-
30
- def defined_stored_pms_names
31
- i_am_i_can.permission_model.all.map(&:name)
32
- end
33
-
34
- def defined_stored_permissions
35
- i_am_i_can.permission_model.all.map { |pms| [ pms.name, pms.desc ] }.to_h
36
- end
37
-
38
- def defined_permissions
39
- defined_local_permissions.deep_merge(defined_stored_permissions)
40
- end
41
-
42
- def pms_of_defined_local_role(role_name)
43
- i_am_i_can.subject_model.defined_local_roles[role_name.to_sym]&.[](:permissions) || []
44
- end
45
- end
46
-
47
- module Ins
48
- def _pms_assignment_result(preds, obj, not_defined_items, covered_items = nil, strict_mode = false)
49
- prefix = 'Permission Assignment Done'
50
- msg1 = "#{not_defined_items} have not been defined or have been repeatedly assigned" if not_defined_items.present?
51
- msg2 = "#{covered_items} have been covered" if covered_items.present?
52
- fail_msg = prefix + ', but ' + [msg1, msg2].compact.join(', ') if msg1 || msg2
53
- raise Error, fail_msg if (strict_mode || i_am_i_can.strict_mode) && fail_msg
54
- puts fail_msg || prefix unless ENV['ITEST']
55
- prefix.present?
56
- end
57
-
58
- def pms_matched?(pms_name, plist)
59
- i_am_i_can.permission_model.matched?(pms_name, in: plist[:in])
60
- end
61
-
62
- def local_permissions
63
- @local_permissions ||= [ ]
64
- end
65
-
66
- alias local_permission_names local_permissions
67
-
68
- # TODO: show by hash
69
- def permissions
70
- local_permission_names + stored_permission_names
71
- end
72
- end
73
- end
74
- end
75
- end
@@ -1,22 +0,0 @@
1
- module IAmICan
2
- module Permission
3
- class PArray < ::Array
4
- attr_accessor :pms
5
-
6
- def matched?(pms_name)
7
- return false if self.blank?
8
- self.pms = pms_name.to_sym
9
- found? || covered?
10
- end
11
-
12
- def found?
13
- pms.in? self
14
- end
15
-
16
- def covered?
17
- pred, obj_type, obj_id = pms.to_s.split('_')
18
- pred.to_sym.in?(self) || :"#{pred}_#{obj_type}".in?(self)
19
- end
20
- end
21
- end
22
- end
@@ -1,25 +0,0 @@
1
- module IAmICan
2
- module Reflection
3
- extend ActiveSupport::Concern
4
-
5
- class_methods do
6
- # User._roles => 'stored_roles'
7
- %w[ subjects roles role_groups permissions ].each do |k|
8
- define_method "_#{k}" do
9
- v = instance_variable_get("@_#{k}")
10
- return v if v.present?
11
- instance_variable_set("@_#{k}", _reflect_of(k.singularize))
12
- end
13
- end
14
- end
15
-
16
- included do
17
- # user._roles => Association CollectionProxy, same as: `user.stored_roles`
18
- %w[ subjects roles role_groups permissions ].each do |k|
19
- define_method "_#{k}" do
20
- send(self.class.send("_#{k}")) if self.class.send("_#{k}")
21
- end
22
- end
23
- end
24
- end
25
- end
@@ -1,76 +0,0 @@
1
- module IAmICan
2
- module Role
3
- module Helpers
4
- module Cls
5
- def _to_store_role name, **options
6
- return false if i_am_i_can.role_model.exists?(name: name) || i_am_i_can.role_group_model&.exists?(name: name)
7
- i_am_i_can.role_model.create!(name: name, **options)
8
- end
9
-
10
- def _role_definition_result(names, failed_items)
11
- prefix = 'Role Definition Done'
12
- fail_msg = prefix + ", but name #{failed_items} have been used by other role or group" if failed_items.present?
13
- raise Error, fail_msg if i_am_i_can.strict_mode && fail_msg
14
- puts fail_msg || prefix unless ENV['ITEST']
15
- prefix.present?
16
- end
17
-
18
- def defined_local_roles
19
- @local_roles ||= { }
20
- end
21
-
22
- def defined_stored_role_names
23
- i_am_i_can.role_model.pluck(:name).map(&:to_sym)
24
- end
25
-
26
- def defined_stored_roles
27
- i_am_i_can.role_model.all.map { |role| [ role.name.to_sym, role.desc ] }.to_h
28
- end
29
-
30
- def defined_roles
31
- defined_local_roles.deep_merge(defined_stored_roles)
32
- end
33
-
34
- def defined_role_group_names
35
- i_am_i_can.role_group_model.pluck(:name).map(&:to_sym)
36
- end
37
-
38
- def defined_role_groups
39
- i_am_i_can.role_group_model.all.map { |group| [ group.name.to_sym, group.member_names.map(&:to_sym).sort ] }.to_h
40
- end
41
- end
42
-
43
- module Ins
44
- def _role_assignment_result(names, failed_items)
45
- prefix = 'Role Assignment Done'
46
- fail_msg = prefix + ", but #{failed_items} have not been defined or have been repeatedly assigned" if failed_items.present?
47
- raise Error, fail_msg if i_am_i_can.strict_mode && fail_msg
48
- puts fail_msg || prefix unless ENV['ITEST']
49
- prefix.present?
50
- end
51
-
52
- def __role
53
- proc do |role|
54
- next role.to_sym if role.is_a?(String) || role.is_a?(Symbol)
55
- next role.name if role.is_a?(i_am_i_can.role_model)
56
- # raise error
57
- end
58
- end
59
-
60
- def local_role_names
61
- @local_role_names ||= [ ]
62
- end
63
-
64
- def local_roles
65
- defined_local_roles.slice(*local_role_names)
66
- end
67
-
68
- def roles
69
- local_role_names + stored_role_names
70
- end
71
-
72
- alias role_names roles
73
- end
74
- end
75
- end
76
- end