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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +236 -174
- data/lib/generators/i_am_i_can/setup_generator.rb +3 -7
- data/lib/generators/i_am_i_can/templates/migrations/i_am_i_can.erb +8 -8
- data/lib/generators/i_am_i_can/templates/models/permission.erb +4 -2
- data/lib/generators/i_am_i_can/templates/models/role.erb +3 -1
- data/lib/generators/i_am_i_can/templates/models/role_group.erb +3 -1
- data/lib/i_am_i_can/configs/config.rb +2 -3
- data/lib/i_am_i_can/configs/configs.rb +1 -7
- data/lib/i_am_i_can/helpers/dynamic.rb +102 -0
- data/lib/i_am_i_can/helpers/result_of.rb +71 -0
- data/lib/i_am_i_can/permission/assignment.rb +12 -60
- data/lib/i_am_i_can/permission/definition.rb +8 -28
- data/lib/i_am_i_can/permission.rb +18 -24
- data/lib/i_am_i_can/resource.rb +24 -19
- data/lib/i_am_i_can/role/assignment.rb +24 -45
- data/lib/i_am_i_can/role/definition.rb +17 -47
- data/lib/i_am_i_can/role.rb +14 -0
- data/lib/i_am_i_can/role_group/assignment.rb +6 -0
- data/lib/i_am_i_can/role_group/definition.rb +25 -0
- data/lib/i_am_i_can/subject/permission_querying.rb +28 -40
- data/lib/i_am_i_can/subject/role_querying.rb +8 -8
- data/lib/i_am_i_can/subject.rb +0 -10
- data/lib/i_am_i_can/support/association_class_methods.rb +43 -0
- data/lib/i_am_i_can/{configurable.rb → support/configurable.rb} +0 -7
- data/lib/i_am_i_can/support/reflection.rb +36 -0
- data/lib/i_am_i_can/version.rb +1 -1
- data/lib/i_am_i_can.rb +33 -16
- metadata +9 -9
- data/Gemfile.lock +0 -121
- data/lib/i_am_i_can/dynamic_generate.rb +0 -95
- data/lib/i_am_i_can/permission/helpers.rb +0 -75
- data/lib/i_am_i_can/permission/p_array.rb +0 -22
- data/lib/i_am_i_can/reflection.rb +0 -25
- 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
|